Set up

Packages

# Wrangling
library(tidyverse)
library(mgsub)

# Statistics/Numerical processing
library(brms)

# PCA
library(FactoMineR) 
library(factoextra) 
library(GPArotation)
library(paran)

# Plotting
library(ggplot2)
library(ghibli)

# Optional settings
options(dplyr.summarise.inform=F) # Stop dplyr from printing summarise error (that isn't an error)
select <- dplyr::select # Ensure that select() command is the dplyr command (clashes with MASS, which is imported/required by paran)

Functions

# Standard error function
std.error <- function(x, na.rm = T) {
  sqrt(var(x, na.rm = na.rm)/length(x[complete.cases(x)]))
}

# ggplot theme
gg_theme <- function() {
  theme_bw() +
  theme(plot.title=element_text(size=25),
        plot.subtitle=element_text(size=15, face="italic"),
        axis.title=element_text(size=20),
        axis.text=element_text(size=15),
        strip.background =element_rect(fill="white"),
        strip.text = element_text(size=15))+
  theme(legend.title = element_text(size=15, face="bold"),
        legend.text=element_text(size=15))
}

Perception Data

Pre-Process Data

Read & Clean Results

Read in the data from downloaded CSV files from Firebase. Also remove data from subjects who did not complete the study (“returned” on Prolific) or have been identified to be outliers, not following instructions, not fulfilling my participant requirements, etc. Outliers are dentified in a later section below (Outlier Check), while participant requirements are checked in the data from the questionnaire.

# List results files per subject
filelist <- list.files(path="./data/axb_1a/perception/", pattern=".csv",full.names=TRUE) 

# Check Number of files
paste("Total number of perception results files in directory:",length(filelist)) 
[1] "Total number of perception results files in directory: 134"
paste("Expected number of questionnaire files:",length(filelist)-2-2) # -2 (repeats) -2 (returns) 
[1] "Expected number of questionnaire files: 130"

In this case, when reading in the data by participant file, the experiment start time is extracted from the structure ./data/axb_XX/perception/subjnumber_starttime.csv where I first remove the “.csv” with gsub, split the string into three based on "_", then select the third item from the first output object ([[1]][3]).

# Read and Concatenate results
## (1) Just read and concat
# condata.read <- do.call(rbind, lapply(filelist, read.csv))

## (2) Read, concat and extract part of filename
condata.read <- do.call(rbind, lapply(filelist, function(x) cbind(read.csv(x),
                                      starttime=strsplit(gsub(".csv","",x), "_")[[1]][3])))
## TODO: Update with subject numbers as necessary
condata.read <- condata.read %>% 
  
  # Fix data with undefined subject
  mutate(participantId = replace_na(participantId, '5d1e2045a37a4d001a1fc2cb')) %>%
  
  # Remove data from dropped subjects
  subset(participantId != "5f4fc3f3e037580c36d1808e") %>%  #only half data --- condA 
  subset(participantId != "5f2d6b6fb5f3f201942d3eb6") %>%  #grew up in IL --- condB
  subset(participantId != "5f5353ff017c5965165df065") %>%   #grew up in TX --- condB
  subset(participantId != "5c904569bc1a950016fbfc91") %>%   #grew up in NE --- condB 
  subset(participantId != "5e57501c1893b21054dbf993") %>%   #too many unusable data --- condD
  subset(participantId != "5c5067d2c879e900017cde4c") %>%   #too many unusable data --- condD
  subset(participantId != "5eb2f7d3c2c3c90c11cbb1cf") %>%   #too many unusable data --- condD
  subset(participantId != "5e267b418e5af58d037f70f0") %>%   #majority unusable data --- condE
  subset(participantId != "5d2c29f9917e53001a3a5c9d") %>%   #majority unusable data --- condE
  subset(participantId != "5c961ee66357fb0001ef4b4a") %>%   #too many unusable data --- condE#axbdata.ind.s3
  subset(participantId != "5c659f77d0fb37000172f5dd") %>%   #too many unusable data; no LBQ data --- condE
  subset(participantId != "5c8f224c9d2bff0001867ce2") %>%   #returned submission (no LBQ data) --- condE
  subset(participantId != "5f5cc6062074a44b9880e431") %>%   #majority unusable data --- condF
  subset(participantId != "5aa02ab689de8200013f3dab") %>%   #timed out submission --- condF
  
  # Remove levels of dropped subjects
  droplevels()
# Trim unnecesssary columns and rows
condata <- subset(condata.read,,-c(url, internal_node_id, view_history, stimulus, success, key_press, trial_index, 
                                    trial_type, wordStim))

# Keep only tonetest and test rows
# Create subject number column by order of participation (first sorting subjects by starttime, then adding subjnum column)
# Recover vowel data from sentNum column (== Vowel data was accidently left out of stimuli data)
# Manipulate data types
# Reorder columns
condata <- condata %>%
  subset(trial_role == "test" | trial_role == "tonetest") %>%
  
  #arrange(desc(starttime)) %>%
  #mutate(subjNum = as.factor(rep(1:nSubj, each=(nrow(.)/nSubj)))) %>%
  
  mutate(vowel = case_when(between(sentNum, 11, 20) ~ "AU",
                           between(sentNum, 21, 30) ~ "AI")) %>%
  mutate(guiseCombination = case_when(conditionId == "condA" | conditionId == "condB" ~ "match",
                                        conditionId == "condC" | conditionId == "condD" ~ "mismatch",
                                        conditionId == "condE" | conditionId == "condF" ~ "baseline")) %>%
  mutate(speakerOrder = case_when(conditionId == "condA" | conditionId == "condC" | conditionId == "condE" ~ "S3-S9",
                                  conditionId == "condB" | conditionId == "condD" | conditionId == "condF" ~ "S9-S3")) %>%
  
  mutate(rt=as.numeric(rt)) %>%
  mutate_if(is.character, as.factor) %>%
  mutate(time_elapsed_sec = time_elapsed/1000, rt_sec = rt/1000) %>%
  
  select(participantId, conditionId, trial_role, time_elapsed, time_elapsed_sec, rt, rt_sec, everything())

# Check data
condata
#summary(condata)

Check Results

Check Participants

# Check number of data points per subject
# Correct number of data points is 174/180/186 = (168 + 6/12/18) 
(nData.bysubj <- condata %>%
  group_by(conditionId, participantId, starttime) %>%
  count())
# Check number of data points per condition (goal: 40 per condition)
(nSubj.bycond <- nData.bysubj %>%
  group_by(conditionId) %>%
  count())

Troubleshoot participant issues manually and/or by filtering duplicate subject files or those with too few responses.

# Manually scroll to check data as needed
View(nData.bysubj)
# Troubleshoot duplicated participants
## Calculate number of subjects vs data files

paste("Total number of screened perception data files:",nrow(nData.bysubj)) # number of data files
[1] "Total number of screened perception data files: 120"
paste("Total number of unique participant numbers:",length(unique(condata.read$participantId))) # unique subj nums
[1] "Total number of unique participant numbers: 120"
## Identify dups
nData.bysubj$dups = duplicated(nData.bysubj$participantId)
nData.bysubj %>% filter(dups==TRUE)

# Troubleshoot half data
nData.bysubj %>% filter(n<342)
NA

Check Tone Test

# select "Tonetest" data
# Check which participants got 4/6 or below on the headphone/attention check
condata.tones <- condata %>%
  subset(trial_role == "tonetest") %>%
  mutate(correct_response=tolower(correct_response)) %>%
  group_by(participantId, conditionId) %>%
  slice_max(order_by = time_elapsed, n = 6) # get last 6 tone trials, by largest time_elapsed

condata.tones <- condata.tones %>%
  group_by(participantId, conditionId) %>%
  summarise(tonesCorrect = sum(correct_response=="true")) %>%
  ungroup()
condata.tones
# Troubleshoot half data
condata.tones %>% filter(tonesCorrect<5)

Check AXB Trials

# Load stim.durations.final dataframe
load(file="./data/stim_durations.rData")

# Select "Test" data + remove columns for Tonetest data
# Merge tonesCorrect column in for later decisions (e.g. if remove people with low score in tone test)

condata.test <- condata %>%
  subset(trial_role == "test") %>%
  subset(.,,-c(button_pressed, correct_answer, correct_response)) %>%
  droplevels() %>%
  
  merge(., condata.tones, all.x=TRUE) %>%
  merge(., stim.durations.final, all.x=TRUE) %>%
  
  select(participantId, conditionId, trial_role, time_elapsed, time_elapsed_sec, rt, rt_sec, raised_response, everything())
condata.test
# Check data for obvious issues
summary(condata.test)
                  participantId   conditionId  trial_role    time_elapsed     time_elapsed_sec        rt              rt_sec         raised_response vowel      speaker   
 5610c4ea7ffc8a0005811504:  336   condA:6720   test:40320   Min.   :  22385   Min.   :  22.39   Min.   :      0   Min.   :   0.000   false:19849     AI:20160   S3:20160  
 57509d9b363e77000695620b:  336   condB:6720                1st Qu.: 761982   1st Qu.: 761.98   1st Qu.:   3262   1st Qu.:   3.262   true :20471     AU:20160   S9:20160  
 5765b92cf96b100001f64c9a:  336   condC:6720                Median :1263204   Median :1263.20   Median :   3592   Median :   3.592                                        
 57901c44900cc80001d2e9c7:  336   condD:6720                Mean   :1358107   Mean   :1358.11   Mean   :   3992   Mean   :   3.991                                        
 59302683d0003800018f39b0:  336   condE:6720                3rd Qu.:1785733   3rd Qu.:1785.73   3rd Qu.:   4049   3rd Qu.:   4.049                                        
 596016f51d5c3e00012f03c3:  336   condF:6720                Max.   :6413055   Max.   :6413.06   Max.   :2722416   Max.   :2722.416                                        
 (Other)                 :38304                                                                                                                                           
    sentNum      order            step   speakerIdentity speakerGuise guiseName    raised_answer  key_response            starttime     guiseCombination speakerOrder 
 Min.   :11.00   axb:20160   Min.   :2   CN:20160        BL:13440     S3-BL:6720   Min.   :0.0   Min.   :0.0000   1599320556796:  336   baseline:13440   S3-S9:20160  
 1st Qu.:18.75   bxa:20160   1st Qu.:3   MI:20160        CN:13440     S3-CN:6720   1st Qu.:0.0   1st Qu.:0.0000   1599320712659:  336   match   :13440   S9-S3:20160  
 Median :20.50               Median :5                   MI:13440     S3-MI:6720   Median :0.5   Median :1.0000   1599321536428:  336   mismatch:13440                
 Mean   :21.33               Mean   :5                                S9-BL:6720   Mean   :0.5   Mean   :0.6014   1599321623488:  336                                 
 3rd Qu.:23.50               3rd Qu.:7                                S9-CN:6720   3rd Qu.:1.0   3rd Qu.:1.0000   1599321799102:  336                                 
 Max.   :30.00               Max.   :8                                S9-MI:6720   Max.   :1.0   Max.   :1.0000   1599322002660:  336                                 
                                                                                                                  (Other)      :38304                                 
  tonesCorrect      dur_sec          dur_ms     quart_dur_sec    quart_dur_ms 
 Min.   :0.000   Min.   :1.799   Min.   :1799   Min.   :1.349   Min.   :1349  
 1st Qu.:2.750   1st Qu.:2.260   1st Qu.:2260   1st Qu.:1.695   1st Qu.:1695  
 Median :6.000   Median :2.506   Median :2506   Median :1.880   Median :1880  
 Mean   :4.392   Mean   :2.464   Mean   :2464   Mean   :1.848   Mean   :1848  
 3rd Qu.:6.000   3rd Qu.:2.678   3rd Qu.:2678   3rd Qu.:2.009   3rd Qu.:2009  
 Max.   :6.000   Max.   :3.022   Max.   :3022   Max.   :2.266   Max.   :2266  
                                                                              
# Check original data points
(datapoints.og <- nrow(condata.test))
[1] 40320

Check AXB Outliers

# What are the descriptive stats on total experiment time and reaction times?
condata.test.bysubj <- condata.test %>%
  group_by(participantId, conditionId) %>%
  summarize(time_elapsed_min = max(time_elapsed_sec/60), mean_rt_sec = mean(rt_sec), min_rt_sec = min(rt_sec),  max_rt_sec = max(rt_sec), sd_rt_sec = sd(rt_sec)) %>%
  ungroup()
head(condata.test.bysubj)

# Summary of total experiment times
# Check for especially short or long times
condata.test.overall <- condata.test.bysubj %>%
  summarize(median_time = median(time_elapsed_min), mean_time= mean(time_elapsed_min), min_time = min(time_elapsed_min), max_time = max(time_elapsed_min))
condata.test.overall
# RT Outlier check
# Calculate response times that are at least 3 SDs away from the mean
condata.test.timesum <- condata.test %>%
  summarize(meanTime = mean(rt), sdTime = sd(rt), minTime = min(rt), maxTime = max(rt), medianTime = median(rt), iqrTime = IQR(rt), meanStimTime = mean(dur_ms)) %>%
  mutate(sd3 = sdTime*3, iqr3 = iqrTime*3, stimTime10 = meanStimTime+10000)
condata.test.timesum
# Add columns of outlier criteria 
condata.test.check <- condata.test %>%
  mutate(rt.outlier.lower = rt < quart_dur_ms, rt.outlier.upper = rt > (dur_ms + 10000))

# Check list of outliers that were removed
condata.test.outliers <- condata.test.check %>%
  subset(rt.outlier.lower == TRUE | rt.outlier.upper == TRUE)
summary(condata.test.outliers)
                  participantId conditionId trial_role  time_elapsed     time_elapsed_sec        rt                rt_sec          raised_response vowel    speaker 
 5c7d960e461e90000179f6d6: 31   condA:39    test:350   Min.   :  40523   Min.   :  40.52   Min.   :      0.0   Min.   :   0.0000   false:186       AI:164   S3:182  
 5ebac5b2ae6d130365b0ed08: 22   condB:72               1st Qu.: 789082   1st Qu.: 789.08   1st Qu.:    909.5   1st Qu.:   0.9095   true :164       AU:186   S9:168  
 5f05ece827813a0da11cd397: 22   condC:45               Median :1461233   Median :1461.23   Median :  13130.5   Median :  13.1305                                    
 5e72318254cb2015a07ef417: 18   condD:67               Mean   :1514033   Mean   :1514.03   Mean   :  25352.7   Mean   :  25.3527                                    
 5e521b2996dbff237ca41f84: 17   condE:92               3rd Qu.:2104518   3rd Qu.:2104.52   3rd Qu.:  18501.8   3rd Qu.:  18.5018                                    
 5e746f7a64051f3d90ff620f: 16   condF:35               Max.   :4216455   Max.   :4216.45   Max.   :2722416.0   Max.   :2722.4160                                    
 (Other)                 :224                                                                                                                                       
    sentNum      order          step       speakerIdentity speakerGuise guiseName  raised_answer     key_response            starttime   guiseCombination speakerOrder
 Min.   :11.00   axb:176   Min.   :2.000   CN:168          BL:127       S3-BL:45   Min.   :0.0000   Min.   :0.0000   1600713995143: 31   baseline:127     S3-S9:176   
 1st Qu.:18.00   bxa:174   1st Qu.:3.000   MI:182          CN:108       S3-CN:67   1st Qu.:0.0000   1st Qu.:0.0000   1599354613292: 22   match   :111     S9-S3:174   
 Median :20.00             Median :5.000                   MI:115       S3-MI:70   Median :0.0000   Median :1.0000   1599579676992: 22   mismatch:112                 
 Mean   :21.09             Mean   :4.994                                S9-BL:82   Mean   :0.4971   Mean   :0.5771   1600800079717: 18                                
 3rd Qu.:23.00             3rd Qu.:7.000                                S9-CN:41   3rd Qu.:1.0000   3rd Qu.:1.0000   1599863886680: 17                                
 Max.   :30.00             Max.   :8.000                                S9-MI:45   Max.   :1.0000   Max.   :1.0000   1599402567115: 16                                
                                                                                                                     (Other)      :224                                
  tonesCorrect      dur_sec          dur_ms     quart_dur_sec    quart_dur_ms  rt.outlier.lower rt.outlier.upper
 Min.   :0.000   Min.   :1.799   Min.   :1799   Min.   :1.349   Min.   :1349   Mode :logical    Mode :logical   
 1st Qu.:2.000   1st Qu.:2.272   1st Qu.:2272   1st Qu.:1.704   1st Qu.:1704   FALSE:194        FALSE:156       
 Median :3.000   Median :2.540   Median :2540   Median :1.905   Median :1905   TRUE :156        TRUE :194       
 Mean   :3.491   Mean   :2.488   Mean   :2488   Mean   :1.866   Mean   :1866                                    
 3rd Qu.:6.000   3rd Qu.:2.682   3rd Qu.:2682   3rd Qu.:2.011   3rd Qu.:2011                                    
 Max.   :6.000   Max.   :3.022   Max.   :3022   Max.   :2.266   Max.   :2266                                    
                                                                                                                
# Summarize number of outliers attributed to each participant
condata.outliers.bysubj <- condata.test.outliers %>% #filter(conditionId=="condC") %>%
    group_by(participantId, conditionId) %>%
    count(sort=TRUE)
condata.outliers.bysubj
View(condata.test.outliers)
# CondA
#19/336 #0.05654762 subj 5f4fc3f3e037580c36d1808e --- removed (for other reasons)
12/336 #0.03571429 subj 5f498900c3368e3df50ea6ac
4/336 #0.01190476 subj 5c698bdf707a740001032f4e, 5cf308da81ea050017a6151e, 5f5065f8c62ac41e03484ba1

# CondB
22/336 #0.06547619 subj 5f05ece827813a0da11cd397 --- Over 5% of data missing...
16/336 #0.04761905 subj 5e8cd8011a88ad08f181eb96
16/336 #0.04761905 subj 5e746f7a64051f3d90ff620f
7/336 #0.02083333 subj 5f4a4da1575d605c43bef871
#5/336 #0.01488095 subj 5f2d6b6fb5f3f201942d3eb6 --- removed

# CondC
13/336 #0.03869048 subj 5f2d5ea5a073960008ed5894
7/336 #0.02083333 subj 5ec44da606cb7931f04a35e9
6/336 #0.01785714 subj 5f12fa2b44b6a42a83519a79
5/336 #0.01488095 subj 5e8ab4b84d3d6775b807e9ba
4/336 #0.01190476 subj 5765b92cf96b100001f64c9a

# CondD
#119/336 #0.3541667 subj 5c5067d2c879e900017cde4c --- removed
#117/336 #0.3482143 subj 5eb2f7d3c2c3c90c11cbb1cf --- removed
#52/336 #0.1547619 subj 5e57501c1893b21054dbf993 --- removed
22/336 #0.06547619 subj 5ebac5b2ae6d130365b0ed08 --- Over 5% of data missing...
8/336 #0.02380952 subj 5d485db699f83a00012bc391
7/336 #0.02083333 subj 5c5067d2c879e900017cde4c, 5cdf2adac194e800187ad97a
4/336 #0.01190476 subj 5bbbca5d63ea8a00019bd7fa, 5e6cbcbc4b1e3727b86b6327, 5f19fa99263a8c0c22573e08

# CondE
#304/336 #0.9047619 subj 5e267b418e5af58d037f70f0 --- removed
#230/336 #0.6845238 subj 5c659f77d0fb37000172f5dd --- removed
#215/336 #0.639881 subj 5d2c29f9917e53001a3a5c9d --- removed
#157/336 #0.4672619 subj 5c961ee66357fb0001ef4b4a --- removed
31/336 #0.0922619 subj 5c7d960e461e90000179f6d6 ...
18/336 #0.05357143 subj 5e72318254cb2015a07ef417
17/336 #0.05059524 subj 5e521b2996dbff237ca41f84
11/336 #0.0327381 subj 5f285f04a241c5166e68dc95
5/336 #0.01488095 subj 5ef4dde17a4f7c0f80a0c593
4/336 #0.01190476 subj 5c8f224c9d2bff0001867ce2

# CondF
#307/336 #0.9136905 subj 5f5cc6062074a44b9880e431 --- removed
#54/336 #0.1607143 subj 5aa02ab689de8200013f3dab --- removed (for timing out; took 137.58728 min to complete AXB)
16/336 #0.04761905 subj 5e954bac8099ec8c18ba2b69
7/336 #0.02083333 subj 5bdf513338109a0001f474c8

Go back to top and remove outlier participants, if necessary. Then rerun everything up to this point.

Finalize Results

# Remove outliers
condata.test.final <- setdiff(condata.test.check, condata.test.outliers)

# Group data by StimType (i.e. Speaker-SpeakerGuise-Vowel-SentNum)
condata.test.final <- condata.test.final %>%
  unite(token, speaker, sentNum, remove=FALSE) %>%
  
  mutate(word = case_when(token == "S3_21" ~ "bright",
                   token == "S3_22" ~ "device",
                   token == "S3_30" ~ "twice",
                   token == "S9_23" ~ "goodnight",
                   token == "S9_25" ~ "invite",
                   token == "S9_29" ~ "sight",
                   token == "S3_18" ~ "slouch",
                   token == "S3_19" ~ "without",
                   token == "S3_20" ~ "workout",
                   token == "S9_11" ~ "checkout",
                   token == "S9_18" ~ "sprouts",
                   token == "S9_20" ~ "workout")) %>%
  mutate(item = paste0(speaker,"_",word)) %>%
  mutate(respRS = case_when(raised_response == "true" ~ 1,
                            raised_response == "false" ~ 0)) %>%
  
  unite(stimType_byword, speaker, speakerGuise, vowel, word, remove=FALSE) %>%
  unite(stimType_byvowel, speaker, speakerGuise, vowel, remove=FALSE) %>%
  
  mutate(sentNum = as.factor(sentNum)) %>%
  mutate(step = (step-5)) %>%
  
  select(participantId, guiseCombination, step, vowel, speakerGuise, speaker, word, speakerOrder, respRS, stimType_byword, stimType_byvowel, everything())

# Summary
summary(condata.test.final)
                  participantId   guiseCombination      step        vowel      speakerGuise speaker        word           speakerOrder      respRS       stimType_byword   
 5610c4ea7ffc8a0005811504:  336   baseline:13313   Min.   :-3e+00   AI:19996   BL:13313     S3:19978   Length:39970       S3-S9:19984   Min.   :0.0000   Length:39970      
 57509d9b363e77000695620b:  336   match   :13329   1st Qu.:-2e+00   AU:19974   CN:13332     S9:19992   Class :character   S9-S3:19986   1st Qu.:0.0000   Class :character  
 57901c44900cc80001d2e9c7:  336   mismatch:13328   Median : 0e+00              MI:13325                Mode  :character                 Median :1.0000   Mode  :character  
 596016f51d5c3e00012f03c3:  336                    Mean   : 5e-05                                                                       Mean   :0.5081                     
 59a88f5b321f870001d16d68:  336                    3rd Qu.: 2e+00                                                                       3rd Qu.:1.0000                     
 5a8e2e8faa46dd00016bfb5a:  336                    Max.   : 3e+00                                                                       Max.   :1.0000                     
 (Other)                 :37954                                                                                                                                            
 stimType_byvowel   conditionId  trial_role    time_elapsed     time_elapsed_sec        rt            rt_sec       raised_response    token              sentNum     
 Length:39970       condA:6681   test:39970   Min.   :  22385   Min.   :  22.39   Min.   : 1643   Min.   : 1.643   false:19663     Length:39970       20     : 6661  
 Class :character   condB:6648                1st Qu.: 761758   1st Qu.: 761.76   1st Qu.: 3269   1st Qu.: 3.269   true :20307     Class :character   18     : 6657  
 Mode  :character   condC:6675                Median :1262205   Median :1262.20   Median : 3592   Median : 3.592                   Mode  :character   21     : 3336  
                    condD:6653                Mean   :1356742   Mean   :1356.74   Mean   : 3804   Mean   : 3.804                                      23     : 3336  
                    condE:6628                3rd Qu.:1784197   3rd Qu.:1784.20   3rd Qu.: 4040   3rd Qu.: 4.040                                      25     : 3335  
                    condF:6685                Max.   :6413055   Max.   :6413.06   Max.   :12850   Max.   :12.850                                      29     : 3335  
                                                                                                                                                      (Other):13310  
 order       speakerIdentity guiseName    raised_answer  key_response            starttime      tonesCorrect    dur_sec          dur_ms     quart_dur_sec    quart_dur_ms 
 axb:19984   CN:19992        S3-BL:6675   Min.   :0.0   Min.   :0.0000   1599321623488:  336   Min.   :0.0   Min.   :1.799   Min.   :1799   Min.   :1.349   Min.   :1349  
 bxa:19986   MI:19978        S3-CN:6653   1st Qu.:0.0   1st Qu.:0.0000   1599321799102:  336   1st Qu.:3.0   1st Qu.:2.224   1st Qu.:2224   1st Qu.:1.668   1st Qu.:1668  
                             S3-MI:6650   Median :1.0   Median :1.0000   1599322002660:  336   Median :6.0   Median :2.473   Median :2473   Median :1.854   Median :1854  
                             S9-BL:6638   Mean   :0.5   Mean   :0.6016   1599322482285:  336   Mean   :4.4   Mean   :2.464   Mean   :2464   Mean   :1.848   Mean   :1848  
                             S9-CN:6679   3rd Qu.:1.0   3rd Qu.:1.0000   1599325250629:  336   3rd Qu.:6.0   3rd Qu.:2.677   3rd Qu.:2677   3rd Qu.:2.008   3rd Qu.:2008  
                             S9-MI:6675   Max.   :1.0   Max.   :1.0000   1599327399382:  336   Max.   :6.0   Max.   :3.022   Max.   :3022   Max.   :2.266   Max.   :2266  
                                                                         (Other)      :37954                                                                              
 rt.outlier.lower rt.outlier.upper     item          
 Mode :logical    Mode :logical    Length:39970      
 FALSE:39970      FALSE:39970      Class :character  
                                   Mode  :character  
                                                     
                                                     
                                                     
                                                     
# Print data
condata.test.final

# Write to file
write.csv(condata.test.final, 'data/axb_1a_exp_data.csv', row.names=F)
# Final kept data points
(datapoints.final <- nrow(condata.test.final))
[1] 39970
# Final removed data points
datapoints.og-datapoints.final
[1] 350
# Calculate percentage of data removed
(datapoints.og-datapoints.final)/datapoints.og # = 0.008852259 = 0.8% of the data were removed due to responses that were too quick (less than 3/4 of the time into the audio file, before the third token would have played) or too slow (over 10 sec after the end of the audio file, an arbitrarily chosen value that should be enough time if a participant were responding as quickly as possible)
[1] 0.008680556

Summarize Data

Plots

PropRS by Guise

# Get subj means per condition
subj.means <- condata.test.final %>% #filter(participantId!='5e42f74f5b772a18434cabf7') %>%
  group_by(participantId, step, vowel, speaker, speakerGuise) %>%
  summarise(mean.Prop = mean(respRS))

# Get group means and se per condition (by averaging speaker means)
condition.means <- subj.means %>%
  group_by(step, vowel, speaker, speakerGuise) %>%
  summarise(grandM.Prop = mean(mean.Prop), se = std.error(mean.Prop))

# Plot lineplot with error bars on step points
byGuise_prop_plot <- condition.means %>%
  ggplot(aes(x = step, y = grandM.Prop)) +
  geom_point(stat="identity", aes(colour = factor(speakerGuise)), cex=5) +
  geom_line(aes(colour=factor(speakerGuise), linetype=factor(speakerGuise)), lwd=1) +
  geom_errorbar(width = .25, aes(ymin = grandM.Prop-se, ymax = grandM.Prop+se, 
                                 colour = factor(speakerGuise))) +
  facet_grid(speaker~vowel) +
  labs(y = "Proportion 'raised' response", x = "Continuum Step (UR to RS)", color="Guise",
       linetype = "Guise", title="Raising Perception: By Guise") +
  coord_cartesian(ylim=c(0, 1)) +
  scale_x_continuous(breaks = -3:3) +
  scale_color_manual(values=ghibli_palette("PonyoMedium")[c(6,4,3)]) +
  gg_theme()
byGuise_prop_plot

RT by Guise

# Get subj means per condition
subj.means <- condata.test.final %>% 
  group_by(participantId, step, vowel, speaker, speakerGuise) %>%
  summarise(mean.rt = mean(log(rt)))

# Get group means and se per condition (by averaging speaker means)
condition.means <- subj.means %>%
  group_by(step, vowel, speaker, speakerGuise) %>%
  summarise(grandM.rt = mean(mean.rt), se = std.error(mean.rt))

# Plot lineplot with error bars on step points
byGuise_rt_plot <- condition.means %>%
  ggplot(aes(x = step, y = grandM.rt)) +
  geom_point(stat="identity", aes(colour = factor(speakerGuise)), cex=5) +
  geom_line(aes(colour=factor(speakerGuise), linetype=factor(speakerGuise)), lwd=1) +
  geom_errorbar(width = .25, aes(ymin = grandM.rt-se, ymax = grandM.rt+se, colour = factor(speakerGuise))) +
  facet_grid(speaker~vowel) +
  labs(y = "Log Response Time", x = "Continuum Step (UR to RS)", color="Guise",
       linetype = "Guise", title="Reaction Time: By Guise") +
  scale_color_manual(values=ghibli_palette("PonyoMedium")[c(6,4,3)])+
  gg_theme()
byGuise_rt_plot

PropRS by Word

# Get subj means per condition
subj.means <- condata.test.final %>% filter(speaker=="S3") %>%
  group_by(participantId, step, vowel, speakerGuise, speaker, word) %>%
  summarise(mean.Prop = mean(respRS))

# Get group means and se per condition (by averaging speaker means)
condition.means <- subj.means %>%
  group_by(step, vowel, speakerGuise, speaker, word) %>%
  summarise(grandM.Prop = mean(mean.Prop), se = std.error(mean.Prop))

# AI
byWord_prop_plot <- condition.means %>% filter(vowel=="AI") %>%
  ggplot(aes(x = step, y = grandM.Prop)) +
  geom_point(stat="identity", aes(colour = factor(speakerGuise)), cex=5, alpha=0.75) +
  geom_line(aes(colour=factor(speakerGuise), linetype=factor(word)), lwd=1) +
  geom_errorbar(width = .25, aes(ymin = grandM.Prop-se, ymax = grandM.Prop+se, colour = factor(speakerGuise))) +
  facet_grid(speaker~word) +
  labs(y = "Proportion 'raised' response", x = "Continuum Step (UR to RS)", color="Guise",
       linetype = "Word", title="AI Raising Perception: By Word") +
  coord_cartesian(ylim=c(0, 1)) +
  scale_x_continuous(breaks = -3:3) +
  scale_color_manual(values=ghibli_palette("PonyoMedium")[c(6,4,3)])+
  gg_theme()
byWord_prop_plot


# AU
byWord_prop_plot <- condition.means %>% filter(vowel=="AU") %>%
  ggplot(aes(x = step, y = grandM.Prop)) +
  geom_point(stat="identity", aes(colour = factor(speakerGuise)), cex=5, alpha=0.75) +
  geom_line(aes(colour=factor(speakerGuise), linetype=factor(word)), lwd=1) +
  geom_errorbar(width = .25, aes(ymin = grandM.Prop-se, ymax = grandM.Prop+se, colour = factor(speakerGuise))) +
  facet_grid(speaker~word) +
  labs(y = "Proportion 'raised' response", x = "Continuum Step (UR to RS)", color="Guise",
       linetype = "Word", title="AU Raising Perception: By Word") +
  coord_cartesian(ylim=c(0, 1)) +
  scale_x_continuous(breaks = -3:3) +
  scale_color_manual(values=ghibli_palette("PonyoMedium")[c(6,4,3)])+
  gg_theme()
byWord_prop_plot

PropRS by Individual

(adapted from CantoMergers project)

Questionnaire Data

Pre-Process Data

Read & Clean Results

The Qualtrics output includes a text response file and a numerical response file. Because I want to use text for some questions (e.g. IK2, the word selection question) but numbers for other questions (e.g. familiarity scale questions), I need to work with both.

I have downloaded the files and renamed them as ’_text’ and ’_num" files. Specifically, file names have been renamed from the original Qualtrics download name to final_lbq_num.csv and final_lbq_text.csv.

# List results files per subject
There were 29 warnings (use warnings() to see them)
filelist <- list.files(path="./data/axb_1a/questionnaire/", pattern=".csv",full.names=TRUE)

# Read and Concatenate results
# (1) Just read and concat
#condata.read <- do.call(rbind, lapply(filelist, read.csv))

# (2) Read, concat and extract part of filename
quesdata.read <- do.call(rbind, lapply(filelist, function(x) cbind(read.csv(x), dataFormat=strsplit(gsub(".csv","",x), "_")[[1]][4])))

# Check that newly extracted columns are correct (`num` or `text`)
# quesdata.read$dataFormat

# colnames(quesdata.read)

Remove the unnecessarily columns and rows. Also extract the question text while we’re at it (before removing the rows) so that we can refer to the questions as necessary, but they won’t be in the data to be analysed.

# Remove metadata columns (first several)
quesdata <- quesdata.read %>% 
  select(-c(StartDate, EndDate, Status, IPAddress, Progress, Duration..in.seconds., Finished, RecordedDate, ResponseId, RecipientLastName, RecipientFirstName, RecipientEmail, ExternalReference, LocationLatitude, LocationLongitude, DistributionChannel, UserLanguage, PROLIFIC_PID))

# Question reference (if want to look back at question text)
questions <- quesdata %>% slice(1)

# Remove unecessary question header and test data rows + add/fix relevant info + remove data from dropped subjects
quesdata <- quesdata %>%
  # Remove irrelevant rows and removed data
  subset(subjID != "Please check that your Prolific ID is correct, then press the 'next' button to continue with the survey." & subjID !="{\"ImportId\":\"QID78_TEXT\"}") %>%
  subset(subjID != "preview1") %>%
  
  # Fix incorrect subject numbers
  mutate(subjID = gsub("5a5a507d76d1c60001ab2ac71c60001ab2ac7", "5a5a507d76d1c60001ab2ac7", subjID)) %>%
  mutate(subjID = gsub("5f474877452857130314c9d11", "5f474877452857130314c9d1", subjID)) %>%
  droplevels() %>%

  # Merge with perception data (for convenience, uses the minimal dataframe `condata.tones`)
  ## Adds subject and condition info + automatically drops subjects that were screened out based on perception experiment performance/returns
  rename(participantId = subjID) %>%
  merge(., condata.tones) %>%
  mutate(guiseCombination = case_when(conditionId == "condA" | conditionId == "condB" ~ "match",
                                        conditionId == "condC" | conditionId == "condD" ~ "mismatch",
                                        conditionId == "condE" | conditionId == "condF" ~ "baseline")) %>%
  mutate(speakerOrder = case_when(conditionId == "condA" | conditionId == "condC" | conditionId == "condE" ~ "S3-S9",
                                  conditionId == "condB" | conditionId == "condD" | conditionId == "condF" ~ "S9-S3")) %>%
  droplevels()

Question Wording

Here’s the table of the question tags, numbers and text. This interactive table allows for sorting and searching! We can use this to check the exact wording of the questions—all of them as they were shown to the participant.

# Print questions for reference
DT::datatable(questions, 
              options=list(scrollX = TRUE,
                           autoWidth = TRUE,
                           columnDefs = list(list(width = '200px', targets = "_all"))))

Process Demographic Info

# Subset to demographic question columns
quesdata.demo <- quesdata %>% filter(dataFormat == "text") %>%
  select(conditionId, participantId, guiseCombination, speakerOrder, 
         Age, Gender, Ethnicity, SpHDisorder, SpHDisorder_2_TEXT, Degree, LingExp, FirstLang, 
         Loc1_1:Loc6_4) %>%
  
  # Fix spelling errors and variation on demographic questions
  mutate_at(vars(-conditionId, -speakerOrder),tolower) %>%
  mutate_if(is.character, str_trim)

# Check data
quesdata.demo

# Summary
# summary(quesdata.demo)

Check Values

# Quick check via table
ques.demo.sum <- quesdata.demo %>%  select(conditionId, Age, Gender, Ethnicity, Loc1_4)
with(quesdata.demo, unique(Gender))
[1] "female"     "male"       "woman"      "femal"      "female."    "non binary" "cis female" "non-binary"
with(quesdata.demo, unique(Loc1_4))
 [1] "mi"               "michigan"         "mi/usa"           ""                 "mi usa"          
 [6] "michigan/usa"     "georgia"          "illinoise"        "pa"               "mi united states"
[11] "il"               "united states"    "michigan, usa"    "mi, usa"         
with(quesdata.demo, unique(Ethnicity))
 [1] "white"                "caucasian, white"     "black"                "american"            
 [5] "caucasian"            "write"                "dutch american"       "hispanic"            
 [9] "white."               "biracial black/white" "asian (korean)"       "multiracial"         
[13] "african american"     "cauacasian"           "european"             "asian"               
[17] "white/caucasian"      "filipino/white"       "middle eastern"       "mixed"               
[21] "latino"               "am. indian"           "white causasian"      "multi-racial"        

Clean Free Responses

quesdata.demo <- quesdata.demo %>%
  
  mutate(Gender = mgsub(Gender, c("woman.*|.*femal.*", "male|cis male", "non-binary|non binary|nonbinary"), c("f", "m", "nb"))) %>%
  
  mutate_at(vars(starts_with("Loc") & ends_with("_4")), ~ mgsub(.x, c("michig.*|mi[/, ].*"), c("mi"))) %>%
  
  mutate(Ethnicity = mgsub(Ethnicity, c("caucasian|caucasion|cauacasian|american|write|european|dutch.*","african american|african-american", "middle east.*", "latino", "biracial.*|multi.*|mixed"), c("white", "black", "middle-eastern", "hispanic", "multiracial"))) %>%
  mutate(Ethnicity = mgsub(Ethnicity, c("filipino/white","white/hispanic", "am. indian"), c("multiracial","multiracial", "native"), fixed=TRUE)) %>%
  mutate(Ethnicity = mgsub(Ethnicity, c(".*white.*", "black.*", ".*asian.*"), c("white", "black", "asian"))) %>%
  
  # Change vector classes from character class
  mutate_at(vars(Age), as.numeric) %>%
  
  # Select
  select(conditionId, participantId, everything())
  
quesdata.demo
NA

Descriptive Stats

# Ethnicity Counts
quesdata.demo %>% group_by(Ethnicity) %>% count() 

quesdata.demo %>% group_by(Ethnicity, conditionId) %>% count() %>% pivot_wider(Ethnicity, names_from = conditionId, values_from=n)
NA
# Gender Counts
quesdata.demo %>% group_by(Gender) %>% count()

quesdata.demo %>% group_by(Gender, conditionId) %>% count() %>% pivot_wider(Gender, names_from = conditionId, values_from=n)
NA
# Age
quesdata.demo %>% summarise(n=length(conditionId), minAge = min(Age), maxAge = max(Age), meanAge = mean(Age), sdAge = sd(Age))

quesdata.demo %>% group_by(conditionId) %>%
  summarise(n=length(conditionId), minAge = min(Age), maxAge = max(Age), meanAge = mean(Age), sdAge = sd(Age)) %>% ungroup()
NA

Locations List (under dev)

quesdata.loc <- quesdata.demo %>% select(participantId, starts_with("Loc"))
quesdata.loc

loc.code <- data.frame(Loc = unique((quesdata.loc$Loc1_3))) %>%
  rbind(data.frame(Loc = unique((quesdata.loc$Loc2_3)))) %>%
  rbind(data.frame(Loc = unique((quesdata.loc$Loc3_3)))) %>%
  rbind(data.frame(Loc = unique((quesdata.loc$Loc4_3)))) %>%
  rbind(data.frame(Loc = unique((quesdata.loc$Loc5_3)))) %>%
  rbind(data.frame(Loc = unique((quesdata.loc$Loc6_3)))) %>%
  unique()
loc.code

Process Text Responses

# Subset data to text format
quesdata.text <- quesdata %>% filter(dataFormat == "text") %>%
  select(participantId, conditionId, guiseCombination, speakerOrder, everything()) %>%
  select(-c(Age, Gender, Ethnicity, SpHDisorder, SpHDisorder_2_TEXT, Degree, LingExp, FirstLang, 
         Loc1_1:Loc6_4, expPurpose)) %>%
  mutate_if(is.character, as.factor)

quesdata.text.sub <- quesdata.text %>% 
  select(-starts_with("Q"), -SC0, -tonesCorrect) %>%
  droplevels()
quesdata.text.sub

IK2: Word Selection Question

IK2 (Implicit Knowledge Q2) refers to the question where subjects select all the words they think Canadians and Michiganders would pronounce differently (“Which of the following words, if any, do you think would be pronounced differently by someone from Canada, as opposed to someone from Michigan? Please select all that apply.”). The question includes 30 words, 5 of which are target /au/ words and 5 of which are target /ai/ words.

We want to go from the raw data, the selected words, to the number of target words (/au/ and /ai/ raising words) selected. The response format is words separated by commas in one cell. So, we need to separate the strings into separate words, check whether each target word occured, then tabulate the scores. A simple search for word strings won’t work, because some words (e.g. out) are substrings of other words (e.g. about).

My solution was to first separate the single column by commas into multiple columns, one per word. To check whether the word was a response, I implement a count of 1 in a new column if a search function finds the target string in a row. This is done for each target word. Finally, I sum the count columns for /ai/ and /au/ separately to get a score out of 5.

# IK2: Can Word Selection question

# Select only IK2 question + create copied column of Words (for next step)
ik2 <- select(quesdata.text.sub, participantId, IK2.CanWords)
ik2 <- mutate(ik2, Words = IK2.CanWords)

# Separate Words into columns (by comma) + create new columns of word in list per row
# Number of columns must be the same for every row, so find the max number of words selected by any subject (23 here)
# Each subject will have 23 columns, one word per column (Word_1, Word_2...) until no more words (NA if no word)
ik2 <- separate(ik2, "Words", paste("Word", 1:30, sep="_"), sep=",", extra="drop")

# Identify target words in each subjects' responses
# Count 1 if word exists in row; 0 if none
# /au/ targets
ik2 <- mutate(ik2, IK2.au.out = as.integer(apply(ik2, 1, function(x) any(x %in% "out"))),
              IK2.au.about = as.integer(grepl('about',IK2.CanWords)),
              IK2.au.devout = as.integer(grepl('devout',IK2.CanWords)),
              IK2.au.house = as.integer(grepl('house',IK2.CanWords)),
              IK2.au.pouch = as.integer(grepl('pouch',IK2.CanWords)))

# /ai/ targets
ik2 <- mutate(ik2, IK2.ai.like = as.integer(apply(ik2, 1, function(x) any(x %in% "like"))),
              IK2.ai.right = as.integer(apply(ik2, 1, function(x) any(x %in% "right"))),
              IK2.ai.might = as.integer(apply(ik2, 1, function(x) any(x %in% "might"))),
              IK2.ai.unite = as.integer(grepl('unite',IK2.CanWords)),
              IK2.ai.ripe = as.integer(apply(ik2, 1, function(x) any(x %in% "ripe"))))

# Sum of targets selected for /au/ and /ai/
ik2 <- mutate(ik2, IK2.au = rowSums(select(ik2, IK2.au.out:IK2.au.pouch)),
              IK2.ai = rowSums(select(ik2, IK2.ai.like:IK2.ai.ripe)))

# Here are two versions of the data
# ...with score for each target word + sum of /au/ and /ai/ targets selected
ik2.values <- select(ik2, participantId, IK2.au, IK2.ai, IK2.au.out:IK2.ai.ripe)

# ...with only sum of /au/ and /ai/ targets selected
ik2.sum <- select(ik2, participantId, IK2.au:IK2.ai)

Process Num Responses

A few cases where participants do not respond to a question because the answer is ‘no’ results in an ‘NA’ entry. These ’NA’s for specific columns are adjusted “manually” to the correct value.

# Subset data to num format
quesdata.num <- quesdata %>% subset(dataFormat == "num") %>%
  select(participantId, conditionId, guiseCombination, speakerOrder, everything()) %>%
  select(-c(Age, Gender, Ethnicity, SpHDisorder, SpHDisorder_2_TEXT, Degree, LingExp, FirstLang, 
         Loc1_1:Loc6_4, expPurpose)) %>%
  rename(EQ.raws = SC0) %>%
  mutate_at(vars(participantId:speakerOrder), as.factor) %>%
  mutate_if(~ all(grepl('^\\d+$', .x)), as.numeric)

## Further adjustments
quesdata.num.sub <- quesdata.num %>%
  # Convert columns to numeric, leaving non-numeric columns as NA
  mutate_if(is.character, as.numeric) %>%
  # Remove columns that are all NA (specifically, if Sum of that column's NAs is NOT equal to the number of rows, select )
  select_if(colSums(is.na(.)) != nrow(.)) %>%
  # Remove columns of certain types of questions or specific question number
  select(-starts_with("Q"), -starts_with("Lang"), -starts_with("IK2"), -starts_with("ME1"), -ends_with("TEXT")) %>%

  # Adjust values of NA (for cases where they can be interpreted as a 'no' or 'never')
  mutate(Travel.NE_Visits = coalesce(Travel.NE_Visits, 1), Travel.S_Visits = coalesce(Travel.S_Visits, 1),
         Travel.W_Visits = coalesce(Travel.W_Visits, 1), Travel.Can_Visits = coalesce(Travel.Can_Visits, 1),
         Travel.NE_Time = coalesce(Travel.NE_Time, 1), Travel.S_Time = coalesce(Travel.S_Time, 1),
         Travel.W_Time = coalesce(Travel.W_Time, 1), Travel.Can_Time = coalesce(Travel.Can_Time, 1),
         PE1.Relatives = coalesce(PE1.Relatives, 2), PE1.CloseFamFriends = coalesce(PE1.CloseFamFriends, 2),
         EK3.CanAI.Diff = coalesce(EK3.CanAI.Diff, 2), EK4.CanAU.Diff = coalesce(EK4.CanAU.Diff, 2),
         ME3.Sources.OtherMedia_1 = coalesce(ME3.Sources.OtherMedia_1, 1), 
         ME3.Sources.Other_1 = coalesce(ME3.Sources.Other_1, 1),
         ME3.Sources.News_1 = coalesce(ME3.Sources.News_1, 1)) %>%
  droplevels()
Problem with `mutate()` input `Lang1_1`.
ℹ NAs introduced by coercion
ℹ Input `Lang1_1` is `.Primitive("as.double")(Lang1_1)`.NAs introduced by coercionProblem with `mutate()` input `Lang1_2`.
ℹ NAs introduced by coercion
ℹ Input `Lang1_2` is `.Primitive("as.double")(Lang1_2)`.NAs introduced by coercionProblem with `mutate()` input `Lang2_1`.
ℹ NAs introduced by coercion
ℹ Input `Lang2_1` is `.Primitive("as.double")(Lang2_1)`.NAs introduced by coercionProblem with `mutate()` input `Lang2_2`.
ℹ NAs introduced by coercion
ℹ Input `Lang2_2` is `.Primitive("as.double")(Lang2_2)`.NAs introduced by coercionProblem with `mutate()` input `Lang3_1`.
ℹ NAs introduced by coercion
ℹ Input `Lang3_1` is `.Primitive("as.double")(Lang3_1)`.NAs introduced by coercionProblem with `mutate()` input `Lang3_2`.
ℹ NAs introduced by coercion
ℹ Input `Lang3_2` is `.Primitive("as.double")(Lang3_2)`.NAs introduced by coercionProblem with `mutate()` input `Lang4_1`.
ℹ NAs introduced by coercion
ℹ Input `Lang4_1` is `.Primitive("as.double")(Lang4_1)`.NAs introduced by coercionProblem with `mutate()` input `Lang4_2`.
ℹ NAs introduced by coercion
ℹ Input `Lang4_2` is `.Primitive("as.double")(Lang4_2)`.NAs introduced by coercionProblem with `mutate()` input `Lang5_1`.
ℹ NAs introduced by coercion
ℹ Input `Lang5_1` is `.Primitive("as.double")(Lang5_1)`.NAs introduced by coercionProblem with `mutate()` input `Lang5_2`.
ℹ NAs introduced by coercion
ℹ Input `Lang5_2` is `.Primitive("as.double")(Lang5_2)`.NAs introduced by coercionProblem with `mutate()` input `Lang6_1`.
ℹ NAs introduced by coercion
ℹ Input `Lang6_1` is `.Primitive("as.double")(Lang6_1)`.NAs introduced by coercionProblem with `mutate()` input `Lang6_2`.
ℹ NAs introduced by coercion
ℹ Input `Lang6_2` is `.Primitive("as.double")(Lang6_2)`.NAs introduced by coercionProblem with `mutate()` input `Lang7_1`.
ℹ NAs introduced by coercion
ℹ Input `Lang7_1` is `.Primitive("as.double")(Lang7_1)`.NAs introduced by coercionProblem with `mutate()` input `Lang7_2`.
ℹ NAs introduced by coercion
ℹ Input `Lang7_2` is `.Primitive("as.double")(Lang7_2)`.NAs introduced by coercionProblem with `mutate()` input `LangSpeakFreq`.
ℹ NAs introduced by coercion
ℹ Input `LangSpeakFreq` is `.Primitive("as.double")(LangSpeakFreq)`.NAs introduced by coercionProblem with `mutate()` input `LangHearFreq`.
ℹ NAs introduced by coercion
ℹ Input `LangHearFreq` is `.Primitive("as.double")(LangHearFreq)`.NAs introduced by coercionProblem with `mutate()` input `SK1.WhereStandard`.
ℹ NAs introduced by coercion
ℹ Input `SK1.WhereStandard` is `.Primitive("as.double")(SK1.WhereStandard)`.NAs introduced by coercionProblem with `mutate()` input `IK2.CanWords`.
ℹ NAs introduced by coercion
ℹ Input `IK2.CanWords` is `.Primitive("as.double")(IK2.CanWords)`.NAs introduced by coercionProblem with `mutate()` input `EK1.CanSpeak.Diff`.
ℹ NAs introduced by coercion
ℹ Input `EK1.CanSpeak.Diff` is `.Primitive("as.double")(EK1.CanSpeak.Diff)`.NAs introduced by coercionProblem with `mutate()` input `EK2.CanPron.Diff`.
ℹ NAs introduced by coercion
ℹ Input `EK2.CanPron.Diff` is `.Primitive("as.double")(EK2.CanPron.Diff)`.NAs introduced by coercionProblem with `mutate()` input `EK3.CanAI.Diff_1_TEXT`.
ℹ NAs introduced by coercion
ℹ Input `EK3.CanAI.Diff_1_TEXT` is `.Primitive("as.double")(EK3.CanAI.Diff_1_TEXT)`.NAs introduced by coercionProblem with `mutate()` input `EK4.CanAU.Diff_1_TEXT`.
ℹ NAs introduced by coercion
ℹ Input `EK4.CanAU.Diff_1_TEXT` is `.Primitive("as.double")(EK4.CanAU.Diff_1_TEXT)`.NAs introduced by coercionProblem with `mutate()` input `PE1.Relatives_1_TEXT`.
ℹ NAs introduced by coercion
ℹ Input `PE1.Relatives_1_TEXT` is `.Primitive("as.double")(PE1.Relatives_1_TEXT)`.NAs introduced by coercionProblem with `mutate()` input `PE1.CloseFamFriends_1_TEXT`.
ℹ NAs introduced by coercion
ℹ Input `PE1.CloseFamFriends_1_TEXT` is `.Primitive("as.double")(PE1.CloseFamFriends_1_TEXT)`.NAs introduced by coercionProblem with `mutate()` input `ME1.TVShows`.
ℹ NAs introduced by coercion
ℹ Input `ME1.TVShows` is `.Primitive("as.double")(ME1.TVShows)`.NAs introduced by coercionProblem with `mutate()` input `ME3.Sources.OtherMedia_1_TEXT`.
ℹ NAs introduced by coercion
ℹ Input `ME3.Sources.OtherMedia_1_TEXT` is `.Primitive("as.double")(ME3.Sources.OtherMedia_1_TEXT)`.NAs introduced by coercionProblem with `mutate()` input `ME3.Sources.Other_1_TEXT`.
ℹ NAs introduced by coercion
ℹ Input `ME3.Sources.Other_1_TEXT` is `.Primitive("as.double")(ME3.Sources.Other_1_TEXT)`.NAs introduced by coercionProblem with `mutate()` input `dataFormat`.
ℹ NAs introduced by coercion
ℹ Input `dataFormat` is `.Primitive("as.double")(dataFormat)`.NAs introduced by coercion
quesdata.num.sub

Finalize Cleaned Results

# Select and Merge only relavant numerical columns of data for PCA analysis
quesdata.clean <- quesdata.demo %>%
  select(participantId, conditionId, guiseCombination, speakerOrder, Age, Gender, Ethnicity) %>%
  merge(., ik2.values) %>%
  merge(., quesdata.num.sub) %>%
  droplevels()

# quesdata.final
quesdata.clean

Analyze Data

PCA: Awareness & Experience

# Check correlations, which motivate the use of PCA to reduce dimensionality
with(quesdata.clean, cor.test(IK2.ai, IK2.au))

    Pearson's product-moment correlation

data:  IK2.ai and IK2.au
t = 0.10684, df = 118, p-value = 0.9151
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.1697059  0.1887432
sample estimates:
        cor 
0.009834557 
# Test correlations of similar questions
with(quesdata.clean, cor.test(Travel.Can_Visits, Travel.Can_Time))

    Pearson's product-moment correlation

data:  Travel.Can_Visits and Travel.Can_Time
t = 4.8225, df = 118, p-value = 4.271e-06
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.2442879 0.5453413
sample estimates:
      cor 
0.4057623 
with(quesdata.clean, cor.test(SE1.Fam.oot_1, SE2.Freq.Overall_1))

    Pearson's product-moment correlation

data:  SE1.Fam.oot_1 and SE2.Freq.Overall_1
t = 6.3242, df = 118, p-value = 4.725e-09
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.3559947 0.6259258
sample estimates:
      cor 
0.5031317 
with(quesdata.clean, cor.test(SE2.Freq.Overall_1, SE2.Freq.Recent_1))

    Pearson's product-moment correlation

data:  SE2.Freq.Overall_1 and SE2.Freq.Recent_1
t = 15.478, df = 118, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.7492182 0.8701187
sample estimates:
      cor 
0.8185375 
with(quesdata.clean, cor.test(SE2.Freq.Overall_1, SE2.Freq.Child_1))

    Pearson's product-moment correlation

data:  SE2.Freq.Overall_1 and SE2.Freq.Child_1
t = 11.606, df = 118, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.6337845 0.8041026
sample estimates:
      cor 
0.7300876 
with(quesdata.clean, cor.test(SE2.Freq.Recent_1, SE2.Freq.Child_1))

    Pearson's product-moment correlation

data:  SE2.Freq.Recent_1 and SE2.Freq.Child_1
t = 6.2574, df = 118, p-value = 6.521e-09
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.3513380 0.6226779
sample estimates:
     cor 
0.499146 

Run PCA

Packages required for this PCA: * PCA command from FactoMineR library (see index for more info) * paran command from paran library * Varimax command from GPArotations library (https://stats.stackexchange.com/questions/59213/how-to-compute-varimax-rotated-principal-components-in-r)

Packages for visualization of PCA * fviz_pca_ind and fviz_pca_biplot from factoextra

# (0) Select data for PCA — only numerical columns
# names(quesdata.clean)

# Medium trimmed set — removes general Canadian stereotype experience/knowledge, imitation, Sources of CE, hockey
quesdata.pca.med <- select(quesdata.clean, 
                           IK2.au, IK2.ai, 
                           SE1.Fam.oot_1, SE2.Freq.Recent_1:SE2.Freq.Overall_1, 
                           PE2.CanSpeakFreq.Recent_1:PE2.CanSpeakFreq.Overall_1,
                           ME4.CanHearFreq.Recent_1:ME4.CanHearFreq.Overall_1)
quesdata.pca.med
NA
## (1) Run Parallel Analysis with `paran`
# Standard way to decide on the number of factors or components needed in an FA or PCA.
# Prints out a scree plot as well, with the randomized line + unadjusted line
paran(quesdata.pca.med,
      graph = TRUE, color = TRUE, 
      col = c("black", "red", "blue"), lty = c(1, 2, 3), lwd = 1, legend = TRUE, 
      file = "", width = 640, height = 640, grdevice = "png", seed = 0)

Using eigendecomposition of correlation matrix.
Computing: 10%  20%  30%  40%  50%  60%  70%  80%  90%  100%


Results of Horn's Parallel Analysis for component retention
360 iterations, using the mean estimate

-------------------------------------------------- 
Component   Adjusted    Unadjusted    Estimated 
            Eigenvalue  Eigenvalue    Bias 
-------------------------------------------------- 
1           4.971821    5.526365      0.554543
2           1.092396    1.490719      0.398322
-------------------------------------------------- 

Adjusted eigenvalues > 1 indicate dimensions to retain.
(2 components retained)

## (2) Run PCA with `FactoMineR`
# ncp = number of components; adjust after checking the parallel analysis output

# FactoMineR PCA Commands
#plbqPCA        # lists commands
#plbqPCA$var    # variables
#plbqPCA$ind    # individuals
#plbqPCA$call   # summary stats

lbqPCA <- PCA(quesdata.pca.med, scale.unit = T, ncp =2, graph=F)

## Relevant Raw PCA Output
# Eigenvalues & percent variance accounted for
(eigenvalues <- lbqPCA$eig)
        eigenvalue percentage of variance cumulative percentage of variance
comp 1  5.52636515             46.0530429                          46.05304
comp 2  1.49071930             12.4226609                          58.47570
comp 3  1.27627799             10.6356499                          69.11135
comp 4  0.98084691              8.1737243                          77.28508
comp 5  0.91569803              7.6308169                          84.91589
comp 6  0.54179449              4.5149541                          89.43085
comp 7  0.49885076              4.1570897                          93.58794
comp 8  0.29356278              2.4463565                          96.03430
comp 9  0.18330456              1.5275380                          97.56183
comp 10 0.16091525              1.3409604                          98.90279
comp 11 0.08765570              0.7304641                          99.63326
comp 12 0.04400908              0.3667424                         100.00000
# Eigenvectors (=Factor matrix, factor score coefficients; sometimes called the factor, but NOT factor scores)
(eigenvectors <- lbqPCA$var$coord)
                                Dim.1       Dim.2
IK2.au                     0.33652887  0.25988343
IK2.ai                     0.07280517 -0.02741285
SE1.Fam.oot_1              0.51820257  0.49540103
SE2.Freq.Recent_1          0.65306541  0.57172271
SE2.Freq.Child_1           0.72740750  0.09144364
SE2.Freq.Overall_1         0.77628179  0.46920650
PE2.CanSpeakFreq.Recent_1  0.74762538 -0.20377204
PE2.CanSpeakFreq.Child_1   0.64620148 -0.55597789
PE2.CanSpeakFreq.Overall_1 0.81985725 -0.31236546
ME4.CanHearFreq.Recent_1   0.78228431  0.04491797
ME4.CanHearFreq.Child_1    0.75019073 -0.38985772
ME4.CanHearFreq.Overall_1  0.87040715 -0.13931773
# Factor loadings (eigenvectors scaled by the square root of their associated eigenvalues)
# Calculate factor loadings using the output eigenvectors and eigenvalues
rawLoadings <- sweep(lbqPCA$var$coord,2,sqrt(lbqPCA$eig[1:ncol(lbqPCA$var$coord),1]),FUN="/")
rawLoadings
                                Dim.1       Dim.2
IK2.au                     0.14315369  0.21285343
IK2.ai                     0.03097009 -0.02245207
SE1.Fam.oot_1              0.22043461  0.40575041
SE2.Freq.Recent_1          0.27780297  0.46826048
SE2.Freq.Child_1           0.30942684  0.07489548
SE2.Freq.Overall_1         0.33021714  0.38429619
PE2.CanSpeakFreq.Recent_1  0.31802719 -0.16689628
PE2.CanSpeakFreq.Child_1   0.27488318 -0.45536493
PE2.CanSpeakFreq.Overall_1 0.34875340 -0.25583801
ME4.CanHearFreq.Recent_1   0.33277051  0.03678935
ME4.CanHearFreq.Child_1    0.31911844 -0.31930683
ME4.CanHearFreq.Overall_1  0.37025648 -0.11410599
# Factor scores for each subject and dimension (also: Individual coordinate scores; principle coordinates)
rawScores <- lbqPCA$ind$coord
## (3) Conduct rotation on the PCA factor loadings with `GPArotation`
# Rotations are typically done on the retained component factor loadings, not on all components nor on the eigenvectors
# Performed for ease of interpretation, maximizing factor loadings
(rotLoadings <- Varimax(rawLoadings)$loadings)
                                 Dim.1        Dim.2
IK2.au                     -0.01960821  0.255763715
IK2.ai                      0.03821973  0.001579207
SE1.Fam.oot_1              -0.07853666  0.455034945
SE2.Freq.Recent_1          -0.07226760  0.539647817
SE2.Freq.Child_1            0.19638308  0.250575317
SE2.Freq.Overall_1          0.02090899  0.506250663
PE2.CanSpeakFreq.Recent_1   0.35301134  0.066171395
PE2.CanSpeakFreq.Child_1    0.49796921 -0.186934875
PE2.CanSpeakFreq.Overall_1  0.43225467  0.015424708
ME4.CanHearFreq.Recent_1    0.23832181  0.235143326
ME4.CanHearFreq.Child_1     0.44834243 -0.052749372
ME4.CanHearFreq.Overall_1   0.36127275  0.139971547
# Recover Rotation matrix from loadings
# Because the rotLoadings are calculated from rawLoadings %*% rotMatrix, can recover rotMatrix by rotLoadings "divided" by rawLoadings, which in matrix multiplication is multiplying by the inverse (transpose) 
# Note: For some reason, can't call Varimax(rawLoadings)$rotmat (just get NULL); this recreates the same matrix from Varimax(rawLoadings)
(rotMatrixL <- t(rawLoadings) %*% rotLoadings)
           Dim.1     Dim.2
Dim.1  0.7847043 0.6198703
Dim.2 -0.6198703 0.7847043
# Calculate rotated factor scores
# The formula simply multiplies the normalized variable scores with the rotation matrix to get rotated factor scores
# First, z-score the raw scores using base R scale()
# Then, matrix multiply the matrix of zScores with the rotation matrix
# Result is a matrix with columns=components and rows=each subject
zScores <- scale(rawScores)
rotScores <- zScores %*% rotMatrixL

Plot PCA

## (4) Data Visualization of Raw Scores with `factoextra`

# Plot individual factor scores
fviz_pca_ind(lbqPCA, col.ind = "#00AFBB", repel = TRUE)


# Biplot, including individual scores and factor vectors
fviz_pca_biplot(lbqPCA, label = "all", col.ind = "#00AFBB", col.var="black", ggtheme = theme_minimal())

## (5) Manual Plots of Rotated Scores with `ggplot`

## Create dataframes of the rotated factor loading and factor score matrices
# Convert rotated factor loadings matrix to data frame; add variable number
rotLoadingsData <- as.data.frame(rotLoadings)
rotLoadingsData <- mutate(rotLoadingsData, variable = row.names(rotLoadings))
rotLoadingsData <- mutate(rotLoadingsData, variable = factor(variable))

# Convert rotated factor score matrix to data frame; add subject number
rotScoreData <- as.data.frame(rotScores)
rotScoreData <- rotScoreData %>% mutate(subject = 1:nrow(.))

## Create base plots
# Loading plot
loadingplot <- rotLoadingsData %>% ggplot(aes(x=Dim.1, y=Dim.2))+
  geom_segment(data=rotLoadingsData, mapping=aes(x=0, y=0, xend=Dim.1*4, yend=Dim.2*4), arrow=arrow(), size=0.5, color="black") +
  geom_text(data=rotLoadingsData, aes(x=Dim.1*4, y=Dim.2*4, label=variable), color="red",check_overlap=T) +
  scale_x_continuous(lim=c(-2.75, 2.75),breaks=seq(-3,3,1)) +
  scale_y_continuous(lim=c(-3.5, 3.5),breaks=seq(-3,3,1)) +
  geom_hline(yintercept=0, linetype="dashed") +
  geom_vline(xintercept=0, linetype="dashed") +
  labs(title="Variables - PCA", x="Dim 1 (36.4%)", y="Dim 2 (17.7%)") +
  gg_theme()
loadingplot


# Scatter plot of Individual factor scores
dimplot = ggplot(rotScoreData, aes(x=Dim.1, y=Dim.2))+
  geom_point(na.rm=TRUE, color="#00AFBB") +
  geom_text(aes(label=subject),hjust=1.5,vjust=1.5, color="#00AFBB", check_overlap=T)+
  scale_x_continuous(lim=c(-2.75, 2.75),breaks=seq(-3,3,1)) +
  scale_y_continuous(lim=c(-3.5, 3.5),breaks=seq(-3,3,1)) +
  geom_hline(yintercept=0, linetype="dashed") +
  geom_vline(xintercept=0, linetype="dashed") +
  labs(title="Individuals - PCA", x="Dim 1 (36.4%)", y="Dim 2 (17.7%)") +
  gg_theme()
dimplot


## Merge loading and score plot = Biplot

# Biplot of factor loadings + ind factor scores
ggplot(rotScoreData, aes(x=Dim.1, y=Dim.2))+
  geom_point(na.rm=TRUE, color="#00AFBB") +
  geom_text(aes(label=subject),hjust=1.5,vjust=1.5, color="#00AFBB", check_overlap=T)+
  
  # Overlay loading plot (i.e. arrows)
  geom_segment(data=rotLoadingsData, mapping=aes(x=0, y=0, xend=Dim.1*4, yend=Dim.2*4), arrow=arrow(), size=0.5, color="black") +
  geom_text(data=rotLoadingsData, aes(x=Dim.1*4.5, y=Dim.2*4.5, label=variable), color="red",check_overlap=T, nudge_y = 0)+

  scale_x_continuous(lim=c(-2.75, 2.75),breaks=seq(-3,3,1)) +
  scale_y_continuous(lim=c(-3.5, 3.5),breaks=seq(-3,3,1)) +
  geom_hline(yintercept=0, linetype="dashed") +
  geom_vline(xintercept=0, linetype="dashed") +
  labs(title="Biplot - PCA", x="Dim 1 (36.4%)", y="Dim 2 (17.7%)") +
  gg_theme()

Interpret PCA

## Interpret PCs (Dimensions) based on factor loadings
rotLoadings.df <- as.data.frame(rotLoadings) %>%
  rownames_to_column(., "Variables") %>%
  rename(., "PC1"= "Dim.1", "PC2" = "Dim.2")
rotLoadings.df
# PC1 Only Contributors
rotLoadings.df %>% filter(abs(PC1) > 0.2)
# PC2 Only Contributors
rotLoadings.df %>% filter(abs(PC2) > 0.2)
# Check for overlapping contributors
rotLoadings.df %>% filter(abs(PC2) > 0.2 & abs(PC1) > 0.2)

# Check for non-contributors
rotLoadings.df %>% filter(abs(PC2) < 0.2 & abs(PC1) < 0.2)

Finalize Results w/ PCA

# For Merging: Convert rotated factor score matrix to data frame; add participantId (assuming order of input dataframe)
indPCAdata <- rotScoreData %>%
  mutate(participantId = quesdata.clean$participantId) %>%
  rename(CEscore = Dim.1) %>%
  rename(SAscore = Dim.2)

# Merge participant data with PC scores 
# Only select the main relevant scores
quesdata.final <- quesdata.clean %>%
  merge(., indPCAdata) %>%
  mutate(MSscore = scale(SK2.MichvStand)) %>%
  mutate(EQscore = scale(EQ.raws)) %>%
  mutate_at(vars(Age), as.numeric) %>%
  mutate_if(is.character, as.factor) %>%
  select(participantId, conditionId, guiseCombination, speakerOrder, Age, Gender, Ethnicity, CEscore, SAscore, MSscore, EQscore, EQ.raws, everything())

summary(quesdata.final)
                  participantId conditionId guiseCombination speakerOrder      Age        Gender 
 5610c4ea7ffc8a0005811504:  1   condA:20    baseline:40      S3-S9:60     Min.   :18.00   f :68  
 57509d9b363e77000695620b:  1   condB:20    match   :40      S9-S3:60     1st Qu.:23.00   m :50  
 5765b92cf96b100001f64c9a:  1   condC:20    mismatch:40                   Median :28.50   nb: 2  
 57901c44900cc80001d2e9c7:  1   condD:20                                  Mean   :33.63          
 59302683d0003800018f39b0:  1   condE:20                                  3rd Qu.:41.00          
 596016f51d5c3e00012f03c3:  1   condF:20                                  Max.   :67.00          
 (Other)                 :114                                                                    
          Ethnicity     CEscore           SAscore             MSscore.V1           EQscore.V1         EQ.raws     
 asian         : 2   Min.   :-1.9258   Min.   :-2.8932   Min.   :-3.0666851   Min.   :-2.2722145   Min.   :17.00  
 black         : 9   1st Qu.:-0.7416   1st Qu.:-0.6085   1st Qu.:-0.3674024   1st Qu.:-0.6553636   1st Qu.:35.75  
 hispanic      : 3   Median :-0.1493   Median : 0.1282   Median : 0.5323585   Median :-0.0301812   Median :43.00  
 middle-eastern: 1   Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.0000000   Mean   : 0.0000000   Mean   :43.35  
 multiracial   : 5   3rd Qu.: 0.7107   3rd Qu.: 0.6579   3rd Qu.: 0.5323585   3rd Qu.: 0.7459072   3rd Qu.:52.00  
 native        : 1   Max.   : 2.6149   Max.   : 1.9687   Max.   : 1.4321195   Max.   : 2.5567803   Max.   :73.00  
 white         :99                                                                                                
     IK2.au         IK2.ai         IK2.au.out      IK2.au.about  IK2.au.devout    IK2.au.house     IK2.au.pouch
 Min.   :0.00   Min.   :0.0000   Min.   :0.0000   Min.   :0.00   Min.   :0.000   Min.   :0.0000   Min.   :0.0  
 1st Qu.:2.00   1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.00   1st Qu.:1.000   1st Qu.:0.0000   1st Qu.:0.0  
 Median :4.00   Median :0.0000   Median :1.0000   Median :1.00   Median :1.000   Median :1.0000   Median :1.0  
 Mean   :3.25   Mean   :0.8833   Mean   :0.6417   Mean   :0.65   Mean   :0.775   Mean   :0.5833   Mean   :0.6  
 3rd Qu.:5.00   3rd Qu.:1.2500   3rd Qu.:1.0000   3rd Qu.:1.00   3rd Qu.:1.000   3rd Qu.:1.0000   3rd Qu.:1.0  
 Max.   :5.00   Max.   :5.0000   Max.   :1.0000   Max.   :1.00   Max.   :1.000   Max.   :1.0000   Max.   :1.0  
                                                                                                               
  IK2.ai.like   IK2.ai.right    IK2.ai.might  IK2.ai.unite   IK2.ai.ripe     Travel.NE_Visits Travel.S_Visits
 Min.   :0.0   Min.   :0.000   Min.   :0.0   Min.   :0.00   Min.   :0.0000   Min.   :1.000    Min.   :1.000  
 1st Qu.:0.0   1st Qu.:0.000   1st Qu.:0.0   1st Qu.:0.00   1st Qu.:0.0000   1st Qu.:1.000    1st Qu.:2.000  
 Median :0.0   Median :0.000   Median :0.0   Median :0.00   Median :0.0000   Median :2.000    Median :2.000  
 Mean   :0.1   Mean   :0.275   Mean   :0.2   Mean   :0.15   Mean   :0.1583   Mean   :1.867    Mean   :2.158  
 3rd Qu.:0.0   3rd Qu.:1.000   3rd Qu.:0.0   3rd Qu.:0.00   3rd Qu.:0.0000   3rd Qu.:2.000    3rd Qu.:3.000  
 Max.   :1.0   Max.   :1.000   Max.   :1.0   Max.   :1.00   Max.   :1.0000   Max.   :4.000    Max.   :4.000  
                                                                                                             
 Travel.W_Visits Travel.Can_Visits Travel.NE_Time  Travel.S_Time   Travel.W_Time   Travel.Can_Time SK2.MichvStand 
 Min.   :1.000   Min.   :1.000     Min.   :1.000   Min.   :1.000   Min.   :1.000   Min.   :1.000   Min.   :2.000  
 1st Qu.:1.000   1st Qu.:1.000     1st Qu.:1.000   1st Qu.:1.000   1st Qu.:1.000   1st Qu.:1.000   1st Qu.:5.000  
 Median :2.000   Median :2.000     Median :1.000   Median :1.000   Median :1.000   Median :1.000   Median :6.000  
 Mean   :1.708   Mean   :1.942     Mean   :1.333   Mean   :1.458   Mean   :1.325   Mean   :1.158   Mean   :5.408  
 3rd Qu.:2.000   3rd Qu.:2.000     3rd Qu.:1.000   3rd Qu.:2.000   3rd Qu.:1.000   3rd Qu.:1.000   3rd Qu.:6.000  
 Max.   :4.000   Max.   :4.000     Max.   :4.000   Max.   :4.000   Max.   :4.000   Max.   :4.000   Max.   :7.000  
                                                                                                                  
 SK3.CanvStand   IK1.DecideCanada  EK1.CanSpeak    EK2.CanPron      EK3.CanAI     EK3.CanAI.Diff    EK4.CanAU    
 Min.   :2.000   Min.   :2.00     Min.   :1.000   Min.   :1.000   Min.   :1.000   Min.   :1.000   Min.   :1.000  
 1st Qu.:3.000   1st Qu.:2.00     1st Qu.:1.000   1st Qu.:1.000   1st Qu.:1.000   1st Qu.:2.000   1st Qu.:1.000  
 Median :4.000   Median :3.00     Median :1.000   Median :1.000   Median :2.000   Median :2.000   Median :1.000  
 Mean   :4.283   Mean   :3.15     Mean   :1.033   Mean   :1.058   Mean   :1.708   Mean   :1.783   Mean   :1.142  
 3rd Qu.:5.000   3rd Qu.:4.00     3rd Qu.:1.000   3rd Qu.:1.000   3rd Qu.:2.000   3rd Qu.:2.000   3rd Qu.:1.000  
 Max.   :6.000   Max.   :5.00     Max.   :2.000   Max.   :2.000   Max.   :2.000   Max.   :2.000   Max.   :2.000  
                                                                                                                 
 EK4.CanAU.Diff  SE1.Fam.eh_1 SE1.Fam.oot_1   SE1.Fam.sorry_1 SE1.Fam.washroom_1 SE1.Fam.nasal_1 SE2.Freq.Recent_1
 Min.   :1.0    Min.   :1.0   Min.   :1.000   Min.   :1.000   Min.   :1.000      Min.   :1.000   Min.   :1.000    
 1st Qu.:1.0    1st Qu.:6.0   1st Qu.:5.000   1st Qu.:3.000   1st Qu.:1.000      1st Qu.:1.000   1st Qu.:2.000    
 Median :1.0    Median :7.0   Median :7.000   Median :6.000   Median :3.000      Median :2.000   Median :4.000    
 Mean   :1.3    Mean   :6.1   Mean   :5.683   Mean   :4.783   Mean   :3.367      Mean   :2.825   Mean   :3.875    
 3rd Qu.:2.0    3rd Qu.:7.0   3rd Qu.:7.000   3rd Qu.:7.000   3rd Qu.:5.250      3rd Qu.:4.000   3rd Qu.:5.000    
 Max.   :2.0    Max.   :7.0   Max.   :7.000   Max.   :7.000   Max.   :7.000      Max.   :7.000   Max.   :7.000    
                                                                                                                  
 SE2.Freq.Child_1 SE2.Freq.Overall_1  SE3.Accuracy   SE4.CanHearImitate SE4.auHearImitate SE5.CanImitate 
 Min.   :1.000    Min.   :1.000      Min.   :1.000   Min.   :1.000      Min.   :1.000     Min.   :1.000  
 1st Qu.:2.000    1st Qu.:3.000      1st Qu.:4.750   1st Qu.:2.000      1st Qu.:3.000     1st Qu.:1.000  
 Median :4.000    Median :4.000      Median :5.000   Median :3.000      Median :5.000     Median :2.000  
 Mean   :3.692    Mean   :4.092      Mean   :4.758   Mean   :3.225      Mean   :4.608     Mean   :2.142  
 3rd Qu.:5.000    3rd Qu.:5.000      3rd Qu.:5.000   3rd Qu.:4.000      3rd Qu.:6.000     3rd Qu.:3.000  
 Max.   :7.000    Max.   :7.000      Max.   :7.000   Max.   :7.000      Max.   :7.000     Max.   :6.000  
                                                                                                         
 SE5.auImitate    PE1.KnowCan    PE1.Relatives   PE1.CloseFamFriends PE2.CanSpeakFreq.Recent_1
 Min.   :1.000   Min.   :1.000   Min.   :1.000   Min.   :1.0         Min.   :1.000            
 1st Qu.:1.000   1st Qu.:1.000   1st Qu.:2.000   1st Qu.:1.0         1st Qu.:2.000            
 Median :2.000   Median :1.000   Median :2.000   Median :2.0         Median :3.000            
 Mean   :2.958   Mean   :1.367   Mean   :1.867   Mean   :1.7         Mean   :3.125            
 3rd Qu.:5.000   3rd Qu.:2.000   3rd Qu.:2.000   3rd Qu.:2.0         3rd Qu.:4.000            
 Max.   :7.000   Max.   :2.000   Max.   :2.000   Max.   :2.0         Max.   :7.000            
                                                                                              
 PE2.CanSpeakFreq.Child_1 PE2.CanSpeakFreq.Overall_1 ME2.HockeyFreq ME3.Sources.People_1 ME3.Sources.TV_1
 Min.   :1.000            Min.   :1.00               Min.   :1.0    Min.   :1.000        Min.   :1.000   
 1st Qu.:1.000            1st Qu.:2.00               1st Qu.:1.0    1st Qu.:1.000        1st Qu.:2.000   
 Median :2.000            Median :3.00               Median :2.0    Median :2.000        Median :3.000   
 Mean   :2.658            Mean   :3.15               Mean   :2.4    Mean   :2.283        Mean   :2.817   
 3rd Qu.:4.000            3rd Qu.:4.00               3rd Qu.:3.0    3rd Qu.:3.000        3rd Qu.:4.000   
 Max.   :7.000            Max.   :7.00               Max.   :7.0    Max.   :7.000        Max.   :6.000   
                                                                                                         
 ME3.Sources.News_1 ME3.Sources.Hockey_1 ME3.Sources.Online_1 ME3.Sources.OtherMedia_1 ME3.Sources.Other_1
 Min.   :1.000      Min.   :1.000        Min.   :1.000        Min.   :1.0              Min.   :1.000      
 1st Qu.:1.000      1st Qu.:1.000        1st Qu.:2.000        1st Qu.:1.0              1st Qu.:1.000      
 Median :2.000      Median :2.000        Median :3.000        Median :1.0              Median :1.000      
 Mean   :2.042      Mean   :2.342        Mean   :2.958        Mean   :1.3              Mean   :1.208      
 3rd Qu.:3.000      3rd Qu.:3.000        3rd Qu.:4.000        3rd Qu.:1.0              3rd Qu.:1.000      
 Max.   :5.000      Max.   :7.000        Max.   :7.000        Max.   :6.0              Max.   :7.000      
                                                                                                          
 ME4.CanHearFreq.Recent_1 ME4.CanHearFreq.Child_1 ME4.CanHearFreq.Overall_1  tonesCorrect      subject      
 Min.   :1.000            Min.   :1.000           Min.   :1.000             Min.   :0.000   Min.   :  1.00  
 1st Qu.:2.750            1st Qu.:2.000           1st Qu.:2.000             1st Qu.:2.750   1st Qu.: 30.75  
 Median :4.000            Median :3.000           Median :3.500             Median :6.000   Median : 60.50  
 Mean   :3.717            Mean   :3.067           Mean   :3.492             Mean   :4.392   Mean   : 60.50  
 3rd Qu.:5.000            3rd Qu.:4.000           3rd Qu.:4.000             3rd Qu.:6.000   3rd Qu.: 90.25  
 Max.   :7.000            Max.   :7.000           Max.   :6.000             Max.   :6.000   Max.   :120.00  
                                                                                                            
quesdata.final

# Write to file
write.csv(quesdata.final, 'data/axb_1a_lbq_data.csv', row.names=F)

Summarize Data

Tables

All Scores

# Total
quesdata.final %>% select(participantId, conditionId, guiseCombination, Age, Gender, Ethnicity, CEscore, SAscore, MSscore, EQscore, EQ.raws) %>%
  summarise_if(is.numeric, list(mean = mean, sd = sd, min = min, max = max)) %>% 
  pivot_longer(everything(), names_to = c("Measure", "Stat"), names_sep = "_", values_to = "value") %>%
  pivot_wider(Measure, names_from = "Stat", values_from = "value") %>%
  mutate(mean = round(mean, digits = 6)) %>%
  mutate(group = "Total") %>%
  select(group, everything())
NA
# Baseline
quesdata.final %>% select(participantId, conditionId, guiseCombination, Age, Gender, Ethnicity, CEscore, SAscore, MSscore, EQscore, EQ.raws) %>%
  filter(guiseCombination == "baseline") %>%
  summarise_if(is.numeric, list(mean = mean, sd = sd, min = min, max = max)) %>% 
  pivot_longer(everything(), names_to = c("Measure", "Stat"), names_sep = "_", values_to = "value") %>%
  pivot_wider(Measure, names_from = "Stat", values_from = "value") %>%
  mutate(mean = round(mean, digits = 6)) %>%
  mutate(group = "baseline") %>%
  select(group, everything())

# Match
quesdata.final %>% select(participantId, conditionId, guiseCombination, Age, Gender, Ethnicity, CEscore, SAscore, MSscore, EQscore, EQ.raws) %>%
  filter(guiseCombination == "match") %>%
  summarise_if(is.numeric, list(mean = mean, sd = sd, min = min, max = max)) %>% 
  pivot_longer(everything(), names_to = c("Measure", "Stat"), names_sep = "_", values_to = "value") %>%
  pivot_wider(Measure, names_from = "Stat", values_from = "value") %>%
  mutate(mean = round(mean, digits = 6)) %>%
  mutate(group = "match") %>%
  select(group, everything())

# Mismatch
quesdata.final %>% select(participantId, conditionId, guiseCombination, Age, Gender, Ethnicity, CEscore, SAscore, MSscore, EQscore, EQ.raws) %>%
  filter(guiseCombination == "mismatch") %>%
  summarise_if(is.numeric, list(mean = mean, sd = sd, min = min, max = max)) %>% 
  pivot_longer(everything(), names_to = c("Measure", "Stat"), names_sep = "_", values_to = "value") %>%
  pivot_wider(Measure, names_from = "Stat", values_from = "value") %>%
  mutate(mean = round(mean, digits = 6)) %>%
  mutate(group = "mismatch") %>%
  select(group, everything())

PCA Contributors

#quesdata.final.sum <- 
  quesdata.final %>% group_by(guiseCombination) %>%
  summarize(#meanEQ = mean(EQscore), 
            meanIK2.au = mean(IK2.au), meanIK2.ai = mean(IK2.ai), 
            #meanDecideCan = mean(IK1.DecideCanada), 
            #meanEhFam = mean(SE1.Fam.eh_1), 
            meanOotFam = mean(SE1.Fam.oot_1), 
            meanSEFreq = mean(SE2.Freq.Overall_1), meanSEFreq.C = mean(SE2.Freq.Child_1), 
            meanSEFreq.R = mean(SE2.Freq.Recent_1), 
            meanSEAcc = mean(SE3.Accuracy))

#quesdata.final.sum <- 
  quesdata.final %>% group_by(guiseCombination) %>%
  summarize(CanHearFreq = mean(ME4.CanHearFreq.Overall_1), 
            CanHearFreq.R = mean(ME4.CanHearFreq.Recent_1),
            CanHearFreq.C = mean(ME4.CanHearFreq.Child_1),
            CanSpeakFreq = mean(PE2.CanSpeakFreq.Overall_1),
            CanSpeakFreq.R = mean(PE2.CanSpeakFreq.Recent_1),
            CanSpeakFreq.C = mean(PE2.CanSpeakFreq.Child_1))

Yes/No Responses

quesdata.final %>% group_by(guiseCombination) %>% mutate(EK1.CanSpeak = ifelse(EK1.CanSpeak==1, "yes", "no")) %>%
count(EK1.CanSpeak) %>%
  pivot_wider(names_from = EK1.CanSpeak, values_from = n) %>%
  mutate(question="SpeakDiff") %>% relocate(question)

quesdata.final %>% group_by(guiseCombination) %>% mutate(EK2.CanPron = ifelse(EK2.CanPron==1, "yes", "no")) %>%
count(EK2.CanPron) %>%
  pivot_wider(names_from = EK2.CanPron, values_from = n)  %>%
  mutate(question="PronounceDiff") %>% relocate(question)

quesdata.final %>% group_by(guiseCombination) %>% mutate(EK3.CanAI = ifelse(EK3.CanAI==1, "yes", "no")) %>%
count(EK3.CanAI) %>%
  pivot_wider(names_from = EK3.CanAI, values_from = n) %>%
  mutate(prop.yes = yes/(yes+no))  %>%
  mutate(question="aiDiff") %>% relocate(question)

quesdata.final %>% group_by(guiseCombination) %>% mutate(EK4.CanAU = ifelse(EK4.CanAU==1, "yes", "no")) %>%
count(EK4.CanAU) %>%
  pivot_wider(names_from = EK4.CanAU, values_from = n)  %>%
  mutate(prop.yes = yes/(yes+no))  %>%
  mutate(question="auDiff") %>% relocate(question)
# Overall total
quesdata.final %>% mutate(EK3.CanAI = ifelse(EK3.CanAI==1, "yes", "no")) %>% count(EK3.CanAI) %>%
  pivot_wider(names_from = EK3.CanAI, values_from = n) %>% mutate(prop.yes = yes/(yes+no))  %>%
  mutate(question="aiDiff") %>% relocate(question) %>%
  rbind(.,quesdata.final %>% mutate(EK4.CanAU = ifelse(EK4.CanAU==1, "yes", "no")) %>% count(EK4.CanAU) %>%
          pivot_wider(names_from = EK4.CanAU, values_from = n)%>% mutate(prop.yes = yes/(yes+no))  %>%
          mutate(question="auDiff") %>% relocate(question)
  )
NA

Plots

EQ Scores

# Density Plot of score distributions
quesdata.final %>% mutate(guiseCombination = plyr::mapvalues(guiseCombination, from = c("baseline", "match", "mismatch"), to = c("No-Guise", "Guise-Match", "Guise-Mismatch"))) %>%
  ggplot(aes(x=EQscore,fill=guiseCombination,color=guiseCombination))+
   geom_density(alpha=0.3) +
  labs(title="", x="EQ Score", y="Count") +
  gg_theme()

# By Gender
ggplot(data=quesdata.final, aes(x=Gender, y=EQscore)) +
  geom_boxplot(aes(linetype = Gender), fill="grey", alpha=0.3, na.rm=TRUE) +
  gg_theme()


# By Gender + Guise
ggplot(data=quesdata.final, aes(x=Gender, y=EQscore)) +
  geom_boxplot(aes(fill = guiseCombination, color=guiseCombination, linetype=Gender), alpha=0.3, na.rm=TRUE) +
  facet_grid(~guiseCombination) +
  scale_color_manual(values=ghibli_palette("PonyoMedium")[c(6,3,4)]) +
  scale_fill_manual(values=ghibli_palette("PonyoMedium")[c(6,3,4)]) +
  gg_theme()


# By Guise
ggplot(data=quesdata.final, aes(x=guiseCombination, y=EQscore)) +
  geom_boxplot(aes(fill = guiseCombination, color=guiseCombination), alpha=0.3, na.rm=TRUE) +
  scale_color_manual(values=ghibli_palette("PonyoMedium")[c(6,3,4)]) +
  scale_fill_manual(values=ghibli_palette("PonyoMedium")[c(6,3,4)]) +
  gg_theme()

SA Scores

# Density Plot of score distributions
quesdata.final %>% mutate(guiseCombination = plyr::mapvalues(guiseCombination, from = c("baseline", "match", "mismatch"), to = c("No-Guise", "Guise-Match", "Guise-Mismatch"))) %>%
  ggplot(aes(x=SAscore,fill=guiseCombination,color=guiseCombination))+
   geom_density(alpha=0.3) +
  labs(title="", x="SA Score", y="Count") +
  gg_theme()

# By Gender
ggplot(data=quesdata.final, aes(x=Gender, y=SAscore)) +
  geom_boxplot(aes(linetype = Gender), fill="grey", alpha=0.3, na.rm=TRUE) +
  gg_theme()


# By Gender + Guise
ggplot(data=quesdata.final, aes(x=Gender, y=SAscore)) +
  geom_boxplot(aes(fill = guiseCombination, color=guiseCombination, linetype=Gender), alpha=0.3, na.rm=TRUE) +
  facet_grid(~guiseCombination) +
  scale_color_manual(values=ghibli_palette("PonyoMedium")[c(6,3,4)]) +
  scale_fill_manual(values=ghibli_palette("PonyoMedium")[c(6,3,4)]) +
  gg_theme()


# By Guise
ggplot(data=quesdata.final, aes(x=guiseCombination, y=SAscore)) +
  geom_boxplot(aes(fill = guiseCombination, color=guiseCombination), alpha=0.3, na.rm=TRUE) +
  scale_color_manual(values=ghibli_palette("PonyoMedium")[c(6,3,4)]) +
  scale_fill_manual(values=ghibli_palette("PonyoMedium")[c(6,3,4)]) +
  gg_theme()

CE Scores

# Density Plot of score distributions
quesdata.final %>% mutate(guiseCombination = plyr::mapvalues(guiseCombination, from = c("baseline", "match", "mismatch"), to = c("No-Guise", "Guise-Match", "Guise-Mismatch"))) %>%
  ggplot(aes(x=CEscore,fill=guiseCombination,color=guiseCombination))+
   geom_density(alpha=0.3) +
  labs(title="", x="CE Score", y="Count") +
  gg_theme()

# By Gender
ggplot(data=quesdata.final, aes(x=Gender, y=CEscore)) +
  geom_boxplot(aes(linetype = Gender), fill="grey", alpha=0.3, na.rm=TRUE) +
  gg_theme()


# By Gender + Guise
ggplot(data=quesdata.final, aes(x=Gender, y=CEscore)) +
  geom_boxplot(aes(fill = guiseCombination, color=guiseCombination, linetype=Gender), alpha=0.3, na.rm=TRUE) +
  facet_grid(~guiseCombination) +
  scale_color_manual(values=ghibli_palette("PonyoMedium")[c(6,3,4)]) +
  scale_fill_manual(values=ghibli_palette("PonyoMedium")[c(6,3,4)]) +
  gg_theme()


# By Guise
ggplot(data=quesdata.final, aes(x=guiseCombination, y=CEscore)) +
  geom_boxplot(aes(fill = guiseCombination, color=guiseCombination), alpha=0.3, na.rm=TRUE) +
  scale_color_manual(values=ghibli_palette("PonyoMedium")[c(6,3,4)]) +
  scale_fill_manual(values=ghibli_palette("PonyoMedium")[c(6,3,4)]) +
  gg_theme()

PCA Output Scores


CSCE.biplot <- quesdata.final %>% mutate(guiseCombination = plyr::mapvalues(guiseCombination, from = c("baseline", "match", "mismatch"), to = c("No-Guise", "Guise-Match", "Guise-Mismatch"))) %>%
ggplot(aes(y=CEscore, x=SAscore, color=guiseCombination, shape=guiseCombination)) + 
  geom_point(na.rm=TRUE, size=3, alpha=0.7) +
  #geom_text(aes(label=subject),hjust=1.5,vjust=1.5, color="#00AFBB", check_overlap=T)+

  scale_x_continuous(lim=c(-2.5, 2.5),breaks=seq(-3,3,1)) +
  scale_y_continuous(lim=c(-3.5, 3.5),breaks=seq(-3,3,1)) +
  geom_hline(yintercept=0, linetype="dashed") +
  geom_vline(xintercept=0, linetype="dashed") +
  labs(y="CE Scores (PC1)", x="SA Scores (PC2)", color="Participant Group", shape="Participant Group") +
  
  scale_color_manual(values=ghibli_palette("PonyoMedium")[c(6,3,4)]) +
  gg_theme()
CSCE.biplot


#ggsave(path="plots", filename="CS-CE_distribution_plot.png", CSCE.biplot, width=16, height=8, units = "in" , dpi=72)

Correlations

quesdata.final %>% 
  ggplot(aes(x = SAscore, y = EQscore)) + 
  geom_point(stat="identity", aes(colour = factor(Gender)), cex=2) +
  geom_smooth(method="lm") +

  labs(y = "EQ Score", x = "SA Score", color="Gender",
       title="Correlations: By Speaker") +
  scale_color_manual(values=ghibli_palette("PonyoLight")[c(4,3,2)])+
  gg_theme()

quesdata.final %>% 
  ggplot(aes(x = SAscore, y = CEscore)) + 
  geom_point(stat="identity", aes(colour = factor(Gender)), cex=2) +
  geom_smooth(method="lm") +

  labs(y = "CE Score", x = "SA Score", color="Gender",
       title="Correlations: By Speaker") +
  scale_color_manual(values=ghibli_palette("PonyoLight")[c(4,3,2)])+
  gg_theme()

quesdata.final %>% 
  ggplot(aes(x = CEscore, y = EQscore)) + 
  geom_point(stat="identity", aes(colour = factor(Gender)), cex=2) +
  geom_smooth(method="lm") +

  labs(y = "EQ Score", x = "CE Score", color="Gender",
       title="Correlations: By Speaker") +
  scale_color_manual(values=ghibli_palette("PonyoLight")[c(4,3,2)])+
  gg_theme()

LS0tCnRpdGxlOiAiTUlDUiBBWEIgRXhwZXJpbWVudCAxYSAoV29yZCBBWEIpIEFuYWx5c2lzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIFNldCB1cAojIyBQYWNrYWdlcwpgYGB7ciwgd2FybmluZz1GfQojIFdyYW5nbGluZwpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShtZ3N1YikKCiMgU3RhdGlzdGljcy9OdW1lcmljYWwgcHJvY2Vzc2luZwpsaWJyYXJ5KGJybXMpCgojIFBDQQpsaWJyYXJ5KEZhY3RvTWluZVIpIApsaWJyYXJ5KGZhY3RvZXh0cmEpIApsaWJyYXJ5KEdQQXJvdGF0aW9uKQpsaWJyYXJ5KHBhcmFuKQoKIyBQbG90dGluZwpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2hpYmxpKQoKIyBPcHRpb25hbCBzZXR0aW5ncwpvcHRpb25zKGRwbHlyLnN1bW1hcmlzZS5pbmZvcm09RikgIyBTdG9wIGRwbHlyIGZyb20gcHJpbnRpbmcgc3VtbWFyaXNlIGVycm9yICh0aGF0IGlzbid0IGFuIGVycm9yKQpzZWxlY3QgPC0gZHBseXI6OnNlbGVjdCAjIEVuc3VyZSB0aGF0IHNlbGVjdCgpIGNvbW1hbmQgaXMgdGhlIGRwbHlyIGNvbW1hbmQgKGNsYXNoZXMgd2l0aCBNQVNTLCB3aGljaCBpcyBpbXBvcnRlZC9yZXF1aXJlZCBieSBwYXJhbikKYGBgCgojIyBGdW5jdGlvbnMKYGBge3IsIHdhcm5pbmc9Rn0KIyBTdGFuZGFyZCBlcnJvciBmdW5jdGlvbgpzdGQuZXJyb3IgPC0gZnVuY3Rpb24oeCwgbmEucm0gPSBUKSB7CiAgc3FydCh2YXIoeCwgbmEucm0gPSBuYS5ybSkvbGVuZ3RoKHhbY29tcGxldGUuY2FzZXMoeCldKSkKfQoKIyBnZ3Bsb3QgdGhlbWUKZ2dfdGhlbWUgPC0gZnVuY3Rpb24oKSB7CiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0yNSksCiAgICAgICAgcGxvdC5zdWJ0aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xNSwgZmFjZT0iaXRhbGljIiksCiAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0yMCksCiAgICAgICAgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE1KSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID1lbGVtZW50X3JlY3QoZmlsbD0id2hpdGUiKSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTUpKSsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSwgZmFjZT0iYm9sZCIpLAogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE1KSkKfQpgYGAKCiMgLi4uCiMgUGVyY2VwdGlvbiBEYXRhCiMjIFByZS1Qcm9jZXNzIERhdGEKIyMjIFJlYWQgJiBDbGVhbiBSZXN1bHRzCgpSZWFkIGluIHRoZSBkYXRhIGZyb20gZG93bmxvYWRlZCBDU1YgZmlsZXMgZnJvbSBGaXJlYmFzZS4gQWxzbyByZW1vdmUgZGF0YSBmcm9tIHN1YmplY3RzIHdobyBkaWQgbm90IGNvbXBsZXRlIHRoZSBzdHVkeSAoInJldHVybmVkIiBvbiBQcm9saWZpYykgb3IgaGF2ZSBiZWVuIGlkZW50aWZpZWQgdG8gYmUgb3V0bGllcnMsIG5vdCBmb2xsb3dpbmcgaW5zdHJ1Y3Rpb25zLCBub3QgZnVsZmlsbGluZyBteSBwYXJ0aWNpcGFudCByZXF1aXJlbWVudHMsIGV0Yy4gT3V0bGllcnMgYXJlIGRlbnRpZmllZCBpbiBhIGxhdGVyIHNlY3Rpb24gYmVsb3cgKE91dGxpZXIgQ2hlY2spLCB3aGlsZSBwYXJ0aWNpcGFudCByZXF1aXJlbWVudHMgYXJlIGNoZWNrZWQgaW4gdGhlIGRhdGEgZnJvbSB0aGUgcXVlc3Rpb25uYWlyZS4KCmBgYHtyfQojIExpc3QgcmVzdWx0cyBmaWxlcyBwZXIgc3ViamVjdApmaWxlbGlzdCA8LSBsaXN0LmZpbGVzKHBhdGg9Ii4vZGF0YS9heGJfMWEvcGVyY2VwdGlvbi8iLCBwYXR0ZXJuPSIuY3N2IixmdWxsLm5hbWVzPVRSVUUpIAoKIyBDaGVjayBOdW1iZXIgb2YgZmlsZXMKcGFzdGUoIlRvdGFsIG51bWJlciBvZiBwZXJjZXB0aW9uIHJlc3VsdHMgZmlsZXMgaW4gZGlyZWN0b3J5OiIsbGVuZ3RoKGZpbGVsaXN0KSkgCnBhc3RlKCJFeHBlY3RlZCBudW1iZXIgb2YgcXVlc3Rpb25uYWlyZSBmaWxlczoiLGxlbmd0aChmaWxlbGlzdCktMi0yKSAjIC0yIChyZXBlYXRzKSAtMiAocmV0dXJucykgCmBgYAoKSW4gdGhpcyBjYXNlLCB3aGVuIHJlYWRpbmcgaW4gdGhlIGRhdGEgYnkgcGFydGljaXBhbnQgZmlsZSwgdGhlIGV4cGVyaW1lbnQgc3RhcnQgdGltZSBpcyBleHRyYWN0ZWQgZnJvbSB0aGUgc3RydWN0dXJlIGAuL2RhdGEvYXhiX1hYL3BlcmNlcHRpb24vc3Viam51bWJlcl9zdGFydHRpbWUuY3N2YCB3aGVyZSBJIGZpcnN0IHJlbW92ZSB0aGUgIi5jc3YiIHdpdGggZ3N1Yiwgc3BsaXQgdGhlIHN0cmluZyBpbnRvIHRocmVlIGJhc2VkIG9uICJfIiwgdGhlbiBzZWxlY3QgdGhlIHRoaXJkIGl0ZW0gZnJvbSB0aGUgZmlyc3Qgb3V0cHV0IG9iamVjdCAoYFtbMV1dWzNdYCkuCgpgYGB7cn0KIyBSZWFkIGFuZCBDb25jYXRlbmF0ZSByZXN1bHRzCiMjICgxKSBKdXN0IHJlYWQgYW5kIGNvbmNhdAojIGNvbmRhdGEucmVhZCA8LSBkby5jYWxsKHJiaW5kLCBsYXBwbHkoZmlsZWxpc3QsIHJlYWQuY3N2KSkKCiMjICgyKSBSZWFkLCBjb25jYXQgYW5kIGV4dHJhY3QgcGFydCBvZiBmaWxlbmFtZQpjb25kYXRhLnJlYWQgPC0gZG8uY2FsbChyYmluZCwgbGFwcGx5KGZpbGVsaXN0LCBmdW5jdGlvbih4KSBjYmluZChyZWFkLmNzdih4KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydHRpbWU9c3Ryc3BsaXQoZ3N1YigiLmNzdiIsIiIseCksICJfIilbWzFdXVszXSkpKQojIyBUT0RPOiBVcGRhdGUgd2l0aCBzdWJqZWN0IG51bWJlcnMgYXMgbmVjZXNzYXJ5CmNvbmRhdGEucmVhZCA8LSBjb25kYXRhLnJlYWQgJT4lIAogIAogICMgRml4IGRhdGEgd2l0aCB1bmRlZmluZWQgc3ViamVjdAogIG11dGF0ZShwYXJ0aWNpcGFudElkID0gcmVwbGFjZV9uYShwYXJ0aWNpcGFudElkLCAnNWQxZTIwNDVhMzdhNGQwMDFhMWZjMmNiJykpICU+JQogIAogICMgUmVtb3ZlIGRhdGEgZnJvbSBkcm9wcGVkIHN1YmplY3RzCiAgc3Vic2V0KHBhcnRpY2lwYW50SWQgIT0gIjVmNGZjM2YzZTAzNzU4MGMzNmQxODA4ZSIpICU+JSAgI29ubHkgaGFsZiBkYXRhIC0tLSBjb25kQSAKICBzdWJzZXQocGFydGljaXBhbnRJZCAhPSAiNWYyZDZiNmZiNWYzZjIwMTk0MmQzZWI2IikgJT4lICAjZ3JldyB1cCBpbiBJTCAtLS0gY29uZEIKICBzdWJzZXQocGFydGljaXBhbnRJZCAhPSAiNWY1MzUzZmYwMTdjNTk2NTE2NWRmMDY1IikgJT4lICAgI2dyZXcgdXAgaW4gVFggLS0tIGNvbmRCCiAgc3Vic2V0KHBhcnRpY2lwYW50SWQgIT0gIjVjOTA0NTY5YmMxYTk1MDAxNmZiZmM5MSIpICU+JSAgICNncmV3IHVwIGluIE5FIC0tLSBjb25kQiAKICBzdWJzZXQocGFydGljaXBhbnRJZCAhPSAiNWU1NzUwMWMxODkzYjIxMDU0ZGJmOTkzIikgJT4lICAgI3RvbyBtYW55IHVudXNhYmxlIGRhdGEgLS0tIGNvbmRECiAgc3Vic2V0KHBhcnRpY2lwYW50SWQgIT0gIjVjNTA2N2QyYzg3OWU5MDAwMTdjZGU0YyIpICU+JSAgICN0b28gbWFueSB1bnVzYWJsZSBkYXRhIC0tLSBjb25kRAogIHN1YnNldChwYXJ0aWNpcGFudElkICE9ICI1ZWIyZjdkM2MyYzNjOTBjMTFjYmIxY2YiKSAlPiUgICAjdG9vIG1hbnkgdW51c2FibGUgZGF0YSAtLS0gY29uZEQKICBzdWJzZXQocGFydGljaXBhbnRJZCAhPSAiNWUyNjdiNDE4ZTVhZjU4ZDAzN2Y3MGYwIikgJT4lICAgI21ham9yaXR5IHVudXNhYmxlIGRhdGEgLS0tIGNvbmRFCiAgc3Vic2V0KHBhcnRpY2lwYW50SWQgIT0gIjVkMmMyOWY5OTE3ZTUzMDAxYTNhNWM5ZCIpICU+JSAgICNtYWpvcml0eSB1bnVzYWJsZSBkYXRhIC0tLSBjb25kRQogIHN1YnNldChwYXJ0aWNpcGFudElkICE9ICI1Yzk2MWVlNjYzNTdmYjAwMDFlZjRiNGEiKSAlPiUgICAjdG9vIG1hbnkgdW51c2FibGUgZGF0YSAtLS0gY29uZEUKICBzdWJzZXQocGFydGljaXBhbnRJZCAhPSAiNWM2NTlmNzdkMGZiMzcwMDAxNzJmNWRkIikgJT4lICAgI3RvbyBtYW55IHVudXNhYmxlIGRhdGE7IG5vIExCUSBkYXRhIC0tLSBjb25kRQogIHN1YnNldChwYXJ0aWNpcGFudElkICE9ICI1YzhmMjI0YzlkMmJmZjAwMDE4NjdjZTIiKSAlPiUgICAjcmV0dXJuZWQgc3VibWlzc2lvbiAobm8gTEJRIGRhdGEpIC0tLSBjb25kRQogIHN1YnNldChwYXJ0aWNpcGFudElkICE9ICI1ZjVjYzYwNjIwNzRhNDRiOTg4MGU0MzEiKSAlPiUgICAjbWFqb3JpdHkgdW51c2FibGUgZGF0YSAtLS0gY29uZEYKICBzdWJzZXQocGFydGljaXBhbnRJZCAhPSAiNWFhMDJhYjY4OWRlODIwMDAxM2YzZGFiIikgJT4lICAgI3RpbWVkIG91dCBzdWJtaXNzaW9uIC0tLSBjb25kRgogIAogICMgUmVtb3ZlIGxldmVscyBvZiBkcm9wcGVkIHN1YmplY3RzCiAgZHJvcGxldmVscygpCgpgYGAKCmBgYHtyfQojIFRyaW0gdW5uZWNlc3NzYXJ5IGNvbHVtbnMgYW5kIHJvd3MKY29uZGF0YSA8LSBzdWJzZXQoY29uZGF0YS5yZWFkLCwtYyh1cmwsIGludGVybmFsX25vZGVfaWQsIHZpZXdfaGlzdG9yeSwgc3RpbXVsdXMsIHN1Y2Nlc3MsIGtleV9wcmVzcywgdHJpYWxfaW5kZXgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmlhbF90eXBlLCB3b3JkU3RpbSkpCgojIEtlZXAgb25seSB0b25ldGVzdCBhbmQgdGVzdCByb3dzCiMgQ3JlYXRlIHN1YmplY3QgbnVtYmVyIGNvbHVtbiBieSBvcmRlciBvZiBwYXJ0aWNpcGF0aW9uIChmaXJzdCBzb3J0aW5nIHN1YmplY3RzIGJ5IHN0YXJ0dGltZSwgdGhlbiBhZGRpbmcgc3Viam51bSBjb2x1bW4pCiMgUmVjb3ZlciB2b3dlbCBkYXRhIGZyb20gc2VudE51bSBjb2x1bW4gKD09IFZvd2VsIGRhdGEgd2FzIGFjY2lkZW50bHkgbGVmdCBvdXQgb2Ygc3RpbXVsaSBkYXRhKQojIE1hbmlwdWxhdGUgZGF0YSB0eXBlcwojIFJlb3JkZXIgY29sdW1ucwpjb25kYXRhIDwtIGNvbmRhdGEgJT4lCiAgc3Vic2V0KHRyaWFsX3JvbGUgPT0gInRlc3QiIHwgdHJpYWxfcm9sZSA9PSAidG9uZXRlc3QiKSAlPiUKICAKICAjYXJyYW5nZShkZXNjKHN0YXJ0dGltZSkpICU+JQogICNtdXRhdGUoc3Viak51bSA9IGFzLmZhY3RvcihyZXAoMTpuU3ViaiwgZWFjaD0obnJvdyguKS9uU3ViaikpKSkgJT4lCiAgCiAgbXV0YXRlKHZvd2VsID0gY2FzZV93aGVuKGJldHdlZW4oc2VudE51bSwgMTEsIDIwKSB+ICJBVSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJldHdlZW4oc2VudE51bSwgMjEsIDMwKSB+ICJBSSIpKSAlPiUKICBtdXRhdGUoZ3Vpc2VDb21iaW5hdGlvbiA9IGNhc2Vfd2hlbihjb25kaXRpb25JZCA9PSAiY29uZEEiIHwgY29uZGl0aW9uSWQgPT0gImNvbmRCIiB+ICJtYXRjaCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25kaXRpb25JZCA9PSAiY29uZEMiIHwgY29uZGl0aW9uSWQgPT0gImNvbmREIiB+ICJtaXNtYXRjaCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25kaXRpb25JZCA9PSAiY29uZEUiIHwgY29uZGl0aW9uSWQgPT0gImNvbmRGIiB+ICJiYXNlbGluZSIpKSAlPiUKICBtdXRhdGUoc3BlYWtlck9yZGVyID0gY2FzZV93aGVuKGNvbmRpdGlvbklkID09ICJjb25kQSIgfCBjb25kaXRpb25JZCA9PSAiY29uZEMiIHwgY29uZGl0aW9uSWQgPT0gImNvbmRFIiB+ICJTMy1TOSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25kaXRpb25JZCA9PSAiY29uZEIiIHwgY29uZGl0aW9uSWQgPT0gImNvbmREIiB8IGNvbmRpdGlvbklkID09ICJjb25kRiIgfiAiUzktUzMiKSkgJT4lCiAgCiAgbXV0YXRlKHJ0PWFzLm51bWVyaWMocnQpKSAlPiUKICBtdXRhdGVfaWYoaXMuY2hhcmFjdGVyLCBhcy5mYWN0b3IpICU+JQogIG11dGF0ZSh0aW1lX2VsYXBzZWRfc2VjID0gdGltZV9lbGFwc2VkLzEwMDAsIHJ0X3NlYyA9IHJ0LzEwMDApICU+JQogIAogIHNlbGVjdChwYXJ0aWNpcGFudElkLCBjb25kaXRpb25JZCwgdHJpYWxfcm9sZSwgdGltZV9lbGFwc2VkLCB0aW1lX2VsYXBzZWRfc2VjLCBydCwgcnRfc2VjLCBldmVyeXRoaW5nKCkpCgojIENoZWNrIGRhdGEKY29uZGF0YQojc3VtbWFyeShjb25kYXRhKQpgYGAKCiMjIyBDaGVjayBSZXN1bHRzCiMjIyMgQ2hlY2sgUGFydGljaXBhbnRzCmBgYHtyfQojIENoZWNrIG51bWJlciBvZiBkYXRhIHBvaW50cyBwZXIgc3ViamVjdAojIENvcnJlY3QgbnVtYmVyIG9mIGRhdGEgcG9pbnRzIGlzIDE3NC8xODAvMTg2ID0gKDE2OCArIDYvMTIvMTgpIAoobkRhdGEuYnlzdWJqIDwtIGNvbmRhdGEgJT4lCiAgZ3JvdXBfYnkoY29uZGl0aW9uSWQsIHBhcnRpY2lwYW50SWQsIHN0YXJ0dGltZSkgJT4lCiAgY291bnQoKSkKYGBgCgpgYGB7cn0KIyBDaGVjayBudW1iZXIgb2YgZGF0YSBwb2ludHMgcGVyIGNvbmRpdGlvbiAoZ29hbDogNDAgcGVyIGNvbmRpdGlvbikKKG5TdWJqLmJ5Y29uZCA8LSBuRGF0YS5ieXN1YmogJT4lCiAgZ3JvdXBfYnkoY29uZGl0aW9uSWQpICU+JQogIGNvdW50KCkpCmBgYAoKVHJvdWJsZXNob290IHBhcnRpY2lwYW50IGlzc3VlcyBtYW51YWxseSBhbmQvb3IgYnkgZmlsdGVyaW5nIGR1cGxpY2F0ZSBzdWJqZWN0IGZpbGVzIG9yIHRob3NlIHdpdGggdG9vIGZldyByZXNwb25zZXMuCgpgYGB7cn0KIyBNYW51YWxseSBzY3JvbGwgdG8gY2hlY2sgZGF0YSBhcyBuZWVkZWQKVmlldyhuRGF0YS5ieXN1YmopCmBgYAoKYGBge3J9CiMgVHJvdWJsZXNob290IGR1cGxpY2F0ZWQgcGFydGljaXBhbnRzCiMjIENhbGN1bGF0ZSBudW1iZXIgb2Ygc3ViamVjdHMgdnMgZGF0YSBmaWxlcwoKcGFzdGUoIlRvdGFsIG51bWJlciBvZiBzY3JlZW5lZCBwZXJjZXB0aW9uIGRhdGEgZmlsZXM6Iixucm93KG5EYXRhLmJ5c3ViaikpICMgbnVtYmVyIG9mIGRhdGEgZmlsZXMKcGFzdGUoIlRvdGFsIG51bWJlciBvZiB1bmlxdWUgcGFydGljaXBhbnQgbnVtYmVyczoiLGxlbmd0aCh1bmlxdWUoY29uZGF0YS5yZWFkJHBhcnRpY2lwYW50SWQpKSkgIyB1bmlxdWUgc3ViaiBudW1zCmBgYAoKCmBgYHtyfQojIyBJZGVudGlmeSBkdXBzCm5EYXRhLmJ5c3ViaiRkdXBzID0gZHVwbGljYXRlZChuRGF0YS5ieXN1YmokcGFydGljaXBhbnRJZCkKbkRhdGEuYnlzdWJqICU+JSBmaWx0ZXIoZHVwcz09VFJVRSkKCiMgVHJvdWJsZXNob290IGhhbGYgZGF0YQpuRGF0YS5ieXN1YmogJT4lIGZpbHRlcihuPDM0MikKCmBgYAoKIyMjIyBDaGVjayBUb25lIFRlc3QKYGBge3J9CiMgc2VsZWN0ICJUb25ldGVzdCIgZGF0YQojIENoZWNrIHdoaWNoIHBhcnRpY2lwYW50cyBnb3QgNC82IG9yIGJlbG93IG9uIHRoZSBoZWFkcGhvbmUvYXR0ZW50aW9uIGNoZWNrCmNvbmRhdGEudG9uZXMgPC0gY29uZGF0YSAlPiUKICBzdWJzZXQodHJpYWxfcm9sZSA9PSAidG9uZXRlc3QiKSAlPiUKICBtdXRhdGUoY29ycmVjdF9yZXNwb25zZT10b2xvd2VyKGNvcnJlY3RfcmVzcG9uc2UpKSAlPiUKICBncm91cF9ieShwYXJ0aWNpcGFudElkLCBjb25kaXRpb25JZCkgJT4lCiAgc2xpY2VfbWF4KG9yZGVyX2J5ID0gdGltZV9lbGFwc2VkLCBuID0gNikgIyBnZXQgbGFzdCA2IHRvbmUgdHJpYWxzLCBieSBsYXJnZXN0IHRpbWVfZWxhcHNlZAoKY29uZGF0YS50b25lcyA8LSBjb25kYXRhLnRvbmVzICU+JQogIGdyb3VwX2J5KHBhcnRpY2lwYW50SWQsIGNvbmRpdGlvbklkKSAlPiUKICBzdW1tYXJpc2UodG9uZXNDb3JyZWN0ID0gc3VtKGNvcnJlY3RfcmVzcG9uc2U9PSJ0cnVlIikpICU+JQogIHVuZ3JvdXAoKQpjb25kYXRhLnRvbmVzCmBgYAoKYGBge3J9CiMgVHJvdWJsZXNob290IGhhbGYgZGF0YQpjb25kYXRhLnRvbmVzICU+JSBmaWx0ZXIodG9uZXNDb3JyZWN0PDUpCmBgYAoKIyMjIyBDaGVjayBBWEIgVHJpYWxzCgpgYGB7cn0KIyBMb2FkIHN0aW0uZHVyYXRpb25zLmZpbmFsIGRhdGFmcmFtZQpsb2FkKGZpbGU9Ii4vZGF0YS9zdGltX2R1cmF0aW9ucy5yRGF0YSIpCgojIFNlbGVjdCAiVGVzdCIgZGF0YSArIHJlbW92ZSBjb2x1bW5zIGZvciBUb25ldGVzdCBkYXRhCiMgTWVyZ2UgdG9uZXNDb3JyZWN0IGNvbHVtbiBpbiBmb3IgbGF0ZXIgZGVjaXNpb25zIChlLmcuIGlmIHJlbW92ZSBwZW9wbGUgd2l0aCBsb3cgc2NvcmUgaW4gdG9uZSB0ZXN0KQoKY29uZGF0YS50ZXN0IDwtIGNvbmRhdGEgJT4lCiAgc3Vic2V0KHRyaWFsX3JvbGUgPT0gInRlc3QiKSAlPiUKICBzdWJzZXQoLiwsLWMoYnV0dG9uX3ByZXNzZWQsIGNvcnJlY3RfYW5zd2VyLCBjb3JyZWN0X3Jlc3BvbnNlKSkgJT4lCiAgZHJvcGxldmVscygpICU+JQogIAogIG1lcmdlKC4sIGNvbmRhdGEudG9uZXMsIGFsbC54PVRSVUUpICU+JQogIG1lcmdlKC4sIHN0aW0uZHVyYXRpb25zLmZpbmFsLCBhbGwueD1UUlVFKSAlPiUKICAKICBzZWxlY3QocGFydGljaXBhbnRJZCwgY29uZGl0aW9uSWQsIHRyaWFsX3JvbGUsIHRpbWVfZWxhcHNlZCwgdGltZV9lbGFwc2VkX3NlYywgcnQsIHJ0X3NlYywgcmFpc2VkX3Jlc3BvbnNlLCBldmVyeXRoaW5nKCkpCmNvbmRhdGEudGVzdApgYGAKCmBgYHtyfQojIENoZWNrIGRhdGEgZm9yIG9idmlvdXMgaXNzdWVzCnN1bW1hcnkoY29uZGF0YS50ZXN0KQpgYGAKCmBgYHtyfQojIENoZWNrIG9yaWdpbmFsIGRhdGEgcG9pbnRzCihkYXRhcG9pbnRzLm9nIDwtIG5yb3coY29uZGF0YS50ZXN0KSkKYGBgCgojIyMjIENoZWNrIEFYQiBPdXRsaWVycwpgYGB7cn0KIyBXaGF0IGFyZSB0aGUgZGVzY3JpcHRpdmUgc3RhdHMgb24gdG90YWwgZXhwZXJpbWVudCB0aW1lIGFuZCByZWFjdGlvbiB0aW1lcz8KY29uZGF0YS50ZXN0LmJ5c3ViaiA8LSBjb25kYXRhLnRlc3QgJT4lCiAgZ3JvdXBfYnkocGFydGljaXBhbnRJZCwgY29uZGl0aW9uSWQpICU+JQogIHN1bW1hcml6ZSh0aW1lX2VsYXBzZWRfbWluID0gbWF4KHRpbWVfZWxhcHNlZF9zZWMvNjApLCBtZWFuX3J0X3NlYyA9IG1lYW4ocnRfc2VjKSwgbWluX3J0X3NlYyA9IG1pbihydF9zZWMpLCAgbWF4X3J0X3NlYyA9IG1heChydF9zZWMpLCBzZF9ydF9zZWMgPSBzZChydF9zZWMpKSAlPiUKICB1bmdyb3VwKCkKaGVhZChjb25kYXRhLnRlc3QuYnlzdWJqKQoKIyBTdW1tYXJ5IG9mIHRvdGFsIGV4cGVyaW1lbnQgdGltZXMKIyBDaGVjayBmb3IgZXNwZWNpYWxseSBzaG9ydCBvciBsb25nIHRpbWVzCmNvbmRhdGEudGVzdC5vdmVyYWxsIDwtIGNvbmRhdGEudGVzdC5ieXN1YmogJT4lCiAgc3VtbWFyaXplKG1lZGlhbl90aW1lID0gbWVkaWFuKHRpbWVfZWxhcHNlZF9taW4pLCBtZWFuX3RpbWU9IG1lYW4odGltZV9lbGFwc2VkX21pbiksIG1pbl90aW1lID0gbWluKHRpbWVfZWxhcHNlZF9taW4pLCBtYXhfdGltZSA9IG1heCh0aW1lX2VsYXBzZWRfbWluKSkKY29uZGF0YS50ZXN0Lm92ZXJhbGwKYGBgCgoKYGBge3J9CiMgUlQgT3V0bGllciBjaGVjawojIENhbGN1bGF0ZSByZXNwb25zZSB0aW1lcyB0aGF0IGFyZSBhdCBsZWFzdCAzIFNEcyBhd2F5IGZyb20gdGhlIG1lYW4KY29uZGF0YS50ZXN0LnRpbWVzdW0gPC0gY29uZGF0YS50ZXN0ICU+JQogIHN1bW1hcml6ZShtZWFuVGltZSA9IG1lYW4ocnQpLCBzZFRpbWUgPSBzZChydCksIG1pblRpbWUgPSBtaW4ocnQpLCBtYXhUaW1lID0gbWF4KHJ0KSwgbWVkaWFuVGltZSA9IG1lZGlhbihydCksIGlxclRpbWUgPSBJUVIocnQpLCBtZWFuU3RpbVRpbWUgPSBtZWFuKGR1cl9tcykpICU+JQogIG11dGF0ZShzZDMgPSBzZFRpbWUqMywgaXFyMyA9IGlxclRpbWUqMywgc3RpbVRpbWUxMCA9IG1lYW5TdGltVGltZSsxMDAwMCkKY29uZGF0YS50ZXN0LnRpbWVzdW0KYGBgCgoKYGBge3J9CiMgQWRkIGNvbHVtbnMgb2Ygb3V0bGllciBjcml0ZXJpYSAKY29uZGF0YS50ZXN0LmNoZWNrIDwtIGNvbmRhdGEudGVzdCAlPiUKICBtdXRhdGUocnQub3V0bGllci5sb3dlciA9IHJ0IDwgcXVhcnRfZHVyX21zLCBydC5vdXRsaWVyLnVwcGVyID0gcnQgPiAoZHVyX21zICsgMTAwMDApKQoKIyBDaGVjayBsaXN0IG9mIG91dGxpZXJzIHRoYXQgd2VyZSByZW1vdmVkCmNvbmRhdGEudGVzdC5vdXRsaWVycyA8LSBjb25kYXRhLnRlc3QuY2hlY2sgJT4lCiAgc3Vic2V0KHJ0Lm91dGxpZXIubG93ZXIgPT0gVFJVRSB8IHJ0Lm91dGxpZXIudXBwZXIgPT0gVFJVRSkKc3VtbWFyeShjb25kYXRhLnRlc3Qub3V0bGllcnMpCgojIFN1bW1hcml6ZSBudW1iZXIgb2Ygb3V0bGllcnMgYXR0cmlidXRlZCB0byBlYWNoIHBhcnRpY2lwYW50CmNvbmRhdGEub3V0bGllcnMuYnlzdWJqIDwtIGNvbmRhdGEudGVzdC5vdXRsaWVycyAlPiUgI2ZpbHRlcihjb25kaXRpb25JZD09ImNvbmRDIikgJT4lCiAgICBncm91cF9ieShwYXJ0aWNpcGFudElkLCBjb25kaXRpb25JZCkgJT4lCiAgICBjb3VudChzb3J0PVRSVUUpCmNvbmRhdGEub3V0bGllcnMuYnlzdWJqCmBgYAoKYGBge3J9ClZpZXcoY29uZGF0YS50ZXN0Lm91dGxpZXJzKQpgYGAKCgpgYGB7cn0KIyBDb25kQQojMTkvMzM2ICMwLjA1NjU0NzYyIHN1YmogNWY0ZmMzZjNlMDM3NTgwYzM2ZDE4MDhlIC0tLSByZW1vdmVkIChmb3Igb3RoZXIgcmVhc29ucykKMTIvMzM2ICMwLjAzNTcxNDI5IHN1YmogNWY0OTg5MDBjMzM2OGUzZGY1MGVhNmFjCjQvMzM2ICMwLjAxMTkwNDc2IHN1YmogNWM2OThiZGY3MDdhNzQwMDAxMDMyZjRlLCA1Y2YzMDhkYTgxZWEwNTAwMTdhNjE1MWUsIDVmNTA2NWY4YzYyYWM0MWUwMzQ4NGJhMQoKIyBDb25kQgoyMi8zMzYgIzAuMDY1NDc2MTkgc3ViaiA1ZjA1ZWNlODI3ODEzYTBkYTExY2QzOTcgLS0tIE92ZXIgNSUgb2YgZGF0YSBtaXNzaW5nLi4uCjE2LzMzNiAjMC4wNDc2MTkwNSBzdWJqIDVlOGNkODAxMWE4OGFkMDhmMTgxZWI5NgoxNi8zMzYgIzAuMDQ3NjE5MDUgc3ViaiA1ZTc0NmY3YTY0MDUxZjNkOTBmZjYyMGYKNy8zMzYgIzAuMDIwODMzMzMgc3ViaiA1ZjRhNGRhMTU3NWQ2MDVjNDNiZWY4NzEKIzUvMzM2ICMwLjAxNDg4MDk1IHN1YmogNWYyZDZiNmZiNWYzZjIwMTk0MmQzZWI2IC0tLSByZW1vdmVkCgojIENvbmRDCjEzLzMzNiAjMC4wMzg2OTA0OCBzdWJqIDVmMmQ1ZWE1YTA3Mzk2MDAwOGVkNTg5NAo3LzMzNiAjMC4wMjA4MzMzMyBzdWJqIDVlYzQ0ZGE2MDZjYjc5MzFmMDRhMzVlOQo2LzMzNiAjMC4wMTc4NTcxNCBzdWJqIDVmMTJmYTJiNDRiNmE0MmE4MzUxOWE3OQo1LzMzNiAjMC4wMTQ4ODA5NSBzdWJqIDVlOGFiNGI4NGQzZDY3NzViODA3ZTliYQo0LzMzNiAjMC4wMTE5MDQ3NiBzdWJqIDU3NjViOTJjZjk2YjEwMDAwMWY2NGM5YQoKIyBDb25kRAojMTE5LzMzNiAjMC4zNTQxNjY3IHN1YmogNWM1MDY3ZDJjODc5ZTkwMDAxN2NkZTRjIC0tLSByZW1vdmVkCiMxMTcvMzM2ICMwLjM0ODIxNDMgc3ViaiA1ZWIyZjdkM2MyYzNjOTBjMTFjYmIxY2YgLS0tIHJlbW92ZWQKIzUyLzMzNiAjMC4xNTQ3NjE5IHN1YmogNWU1NzUwMWMxODkzYjIxMDU0ZGJmOTkzIC0tLSByZW1vdmVkCjIyLzMzNiAjMC4wNjU0NzYxOSBzdWJqIDVlYmFjNWIyYWU2ZDEzMDM2NWIwZWQwOCAtLS0gT3ZlciA1JSBvZiBkYXRhIG1pc3NpbmcuLi4KOC8zMzYgIzAuMDIzODA5NTIgc3ViaiA1ZDQ4NWRiNjk5ZjgzYTAwMDEyYmMzOTEKNy8zMzYgIzAuMDIwODMzMzMgc3ViaiA1YzUwNjdkMmM4NzllOTAwMDE3Y2RlNGMsIDVjZGYyYWRhYzE5NGU4MDAxODdhZDk3YQo0LzMzNiAjMC4wMTE5MDQ3NiBzdWJqIDViYmJjYTVkNjNlYThhMDAwMTliZDdmYSwgNWU2Y2JjYmM0YjFlMzcyN2I4NmI2MzI3LCA1ZjE5ZmE5OTI2M2E4YzBjMjI1NzNlMDgKCiMgQ29uZEUKIzMwNC8zMzYgIzAuOTA0NzYxOSBzdWJqIDVlMjY3YjQxOGU1YWY1OGQwMzdmNzBmMCAtLS0gcmVtb3ZlZAojMjMwLzMzNiAjMC42ODQ1MjM4IHN1YmogNWM2NTlmNzdkMGZiMzcwMDAxNzJmNWRkIC0tLSByZW1vdmVkCiMyMTUvMzM2ICMwLjYzOTg4MSBzdWJqIDVkMmMyOWY5OTE3ZTUzMDAxYTNhNWM5ZCAtLS0gcmVtb3ZlZAojMTU3LzMzNiAjMC40NjcyNjE5IHN1YmogNWM5NjFlZTY2MzU3ZmIwMDAxZWY0YjRhIC0tLSByZW1vdmVkCjMxLzMzNiAjMC4wOTIyNjE5IHN1YmogNWM3ZDk2MGU0NjFlOTAwMDAxNzlmNmQ2IC4uLgoxOC8zMzYgIzAuMDUzNTcxNDMgc3ViaiA1ZTcyMzE4MjU0Y2IyMDE1YTA3ZWY0MTcKMTcvMzM2ICMwLjA1MDU5NTI0IHN1YmogNWU1MjFiMjk5NmRiZmYyMzdjYTQxZjg0CjExLzMzNiAjMC4wMzI3MzgxIHN1YmogNWYyODVmMDRhMjQxYzUxNjZlNjhkYzk1CjUvMzM2ICMwLjAxNDg4MDk1IHN1YmogNWVmNGRkZTE3YTRmN2MwZjgwYTBjNTkzCjQvMzM2ICMwLjAxMTkwNDc2IHN1YmogNWM4ZjIyNGM5ZDJiZmYwMDAxODY3Y2UyCgojIENvbmRGCiMzMDcvMzM2ICMwLjkxMzY5MDUgc3ViaiA1ZjVjYzYwNjIwNzRhNDRiOTg4MGU0MzEgLS0tIHJlbW92ZWQKIzU0LzMzNiAjMC4xNjA3MTQzIHN1YmogNWFhMDJhYjY4OWRlODIwMDAxM2YzZGFiIC0tLSByZW1vdmVkIChmb3IgdGltaW5nIG91dDsgdG9vayAxMzcuNTg3MjggbWluIHRvIGNvbXBsZXRlIEFYQikKMTYvMzM2ICMwLjA0NzYxOTA1IHN1YmogNWU5NTRiYWM4MDk5ZWM4YzE4YmEyYjY5CjcvMzM2ICMwLjAyMDgzMzMzIHN1YmogNWJkZjUxMzMzODEwOWEwMDAxZjQ3NGM4CmBgYAoKR28gYmFjayB0byB0b3AgYW5kIHJlbW92ZSBvdXRsaWVyIHBhcnRpY2lwYW50cywgaWYgbmVjZXNzYXJ5LiBUaGVuIHJlcnVuIGV2ZXJ5dGhpbmcgdXAgdG8gdGhpcyBwb2ludC4KCiMjIyBGaW5hbGl6ZSBSZXN1bHRzCgpgYGB7cn0KIyBSZW1vdmUgb3V0bGllcnMKY29uZGF0YS50ZXN0LmZpbmFsIDwtIHNldGRpZmYoY29uZGF0YS50ZXN0LmNoZWNrLCBjb25kYXRhLnRlc3Qub3V0bGllcnMpCgojIEdyb3VwIGRhdGEgYnkgU3RpbVR5cGUgKGkuZS4gU3BlYWtlci1TcGVha2VyR3Vpc2UtVm93ZWwtU2VudE51bSkKY29uZGF0YS50ZXN0LmZpbmFsIDwtIGNvbmRhdGEudGVzdC5maW5hbCAlPiUKICB1bml0ZSh0b2tlbiwgc3BlYWtlciwgc2VudE51bSwgcmVtb3ZlPUZBTFNFKSAlPiUKICAKICBtdXRhdGUod29yZCA9IGNhc2Vfd2hlbih0b2tlbiA9PSAiUzNfMjEiIH4gImJyaWdodCIsCiAgICAgICAgICAgICAgICAgICB0b2tlbiA9PSAiUzNfMjIiIH4gImRldmljZSIsCiAgICAgICAgICAgICAgICAgICB0b2tlbiA9PSAiUzNfMzAiIH4gInR3aWNlIiwKICAgICAgICAgICAgICAgICAgIHRva2VuID09ICJTOV8yMyIgfiAiZ29vZG5pZ2h0IiwKICAgICAgICAgICAgICAgICAgIHRva2VuID09ICJTOV8yNSIgfiAiaW52aXRlIiwKICAgICAgICAgICAgICAgICAgIHRva2VuID09ICJTOV8yOSIgfiAic2lnaHQiLAogICAgICAgICAgICAgICAgICAgdG9rZW4gPT0gIlMzXzE4IiB+ICJzbG91Y2giLAogICAgICAgICAgICAgICAgICAgdG9rZW4gPT0gIlMzXzE5IiB+ICJ3aXRob3V0IiwKICAgICAgICAgICAgICAgICAgIHRva2VuID09ICJTM18yMCIgfiAid29ya291dCIsCiAgICAgICAgICAgICAgICAgICB0b2tlbiA9PSAiUzlfMTEiIH4gImNoZWNrb3V0IiwKICAgICAgICAgICAgICAgICAgIHRva2VuID09ICJTOV8xOCIgfiAic3Byb3V0cyIsCiAgICAgICAgICAgICAgICAgICB0b2tlbiA9PSAiUzlfMjAiIH4gIndvcmtvdXQiKSkgJT4lCiAgbXV0YXRlKGl0ZW0gPSBwYXN0ZTAoc3BlYWtlciwiXyIsd29yZCkpICU+JQogIG11dGF0ZShyZXNwUlMgPSBjYXNlX3doZW4ocmFpc2VkX3Jlc3BvbnNlID09ICJ0cnVlIiB+IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByYWlzZWRfcmVzcG9uc2UgPT0gImZhbHNlIiB+IDApKSAlPiUKICAKICB1bml0ZShzdGltVHlwZV9ieXdvcmQsIHNwZWFrZXIsIHNwZWFrZXJHdWlzZSwgdm93ZWwsIHdvcmQsIHJlbW92ZT1GQUxTRSkgJT4lCiAgdW5pdGUoc3RpbVR5cGVfYnl2b3dlbCwgc3BlYWtlciwgc3BlYWtlckd1aXNlLCB2b3dlbCwgcmVtb3ZlPUZBTFNFKSAlPiUKICAKICBtdXRhdGUoc2VudE51bSA9IGFzLmZhY3RvcihzZW50TnVtKSkgJT4lCiAgbXV0YXRlKHN0ZXAgPSAoc3RlcC01KSkgJT4lCiAgCiAgc2VsZWN0KHBhcnRpY2lwYW50SWQsIGd1aXNlQ29tYmluYXRpb24sIHN0ZXAsIHZvd2VsLCBzcGVha2VyR3Vpc2UsIHNwZWFrZXIsIHdvcmQsIHNwZWFrZXJPcmRlciwgcmVzcFJTLCBzdGltVHlwZV9ieXdvcmQsIHN0aW1UeXBlX2J5dm93ZWwsIGV2ZXJ5dGhpbmcoKSkKCiMgU3VtbWFyeQpzdW1tYXJ5KGNvbmRhdGEudGVzdC5maW5hbCkKCiMgUHJpbnQgZGF0YQpjb25kYXRhLnRlc3QuZmluYWwKCiMgV3JpdGUgdG8gZmlsZQp3cml0ZS5jc3YoY29uZGF0YS50ZXN0LmZpbmFsLCAnZGF0YS9heGJfMWFfZXhwX2RhdGEuY3N2Jywgcm93Lm5hbWVzPUYpCmBgYAoKYGBge3J9CiMgRmluYWwga2VwdCBkYXRhIHBvaW50cwooZGF0YXBvaW50cy5maW5hbCA8LSBucm93KGNvbmRhdGEudGVzdC5maW5hbCkpCgojIEZpbmFsIHJlbW92ZWQgZGF0YSBwb2ludHMKZGF0YXBvaW50cy5vZy1kYXRhcG9pbnRzLmZpbmFsCgojIENhbGN1bGF0ZSBwZXJjZW50YWdlIG9mIGRhdGEgcmVtb3ZlZAooZGF0YXBvaW50cy5vZy1kYXRhcG9pbnRzLmZpbmFsKS9kYXRhcG9pbnRzLm9nICMgPSAwLjAwODg1MjI1OSA9IDAuOCUgb2YgdGhlIGRhdGEgd2VyZSByZW1vdmVkIGR1ZSB0byByZXNwb25zZXMgdGhhdCB3ZXJlIHRvbyBxdWljayAobGVzcyB0aGFuIDMvNCBvZiB0aGUgdGltZSBpbnRvIHRoZSBhdWRpbyBmaWxlLCBiZWZvcmUgdGhlIHRoaXJkIHRva2VuIHdvdWxkIGhhdmUgcGxheWVkKSBvciB0b28gc2xvdyAob3ZlciAxMCBzZWMgYWZ0ZXIgdGhlIGVuZCBvZiB0aGUgYXVkaW8gZmlsZSwgYW4gYXJiaXRyYXJpbHkgY2hvc2VuIHZhbHVlIHRoYXQgc2hvdWxkIGJlIGVub3VnaCB0aW1lIGlmIGEgcGFydGljaXBhbnQgd2VyZSByZXNwb25kaW5nIGFzIHF1aWNrbHkgYXMgcG9zc2libGUpCmBgYAoKCiMjIFN1bW1hcml6ZSBEYXRhCiMjIyBQbG90cwojIyMjIFByb3BSUyBieSBHdWlzZQpgYGB7cn0KIyBHZXQgc3ViaiBtZWFucyBwZXIgY29uZGl0aW9uCnN1YmoubWVhbnMgPC0gY29uZGF0YS50ZXN0LmZpbmFsICU+JSAKICBncm91cF9ieShwYXJ0aWNpcGFudElkLCBzdGVwLCB2b3dlbCwgc3BlYWtlciwgc3BlYWtlckd1aXNlKSAlPiUKICBzdW1tYXJpc2UobWVhbi5Qcm9wID0gbWVhbihyZXNwUlMpKQoKIyBHZXQgZ3JvdXAgbWVhbnMgYW5kIHNlIHBlciBjb25kaXRpb24gKGJ5IGF2ZXJhZ2luZyBzcGVha2VyIG1lYW5zKQpjb25kaXRpb24ubWVhbnMgPC0gc3Viai5tZWFucyAlPiUKICBncm91cF9ieShzdGVwLCB2b3dlbCwgc3BlYWtlciwgc3BlYWtlckd1aXNlKSAlPiUKICBzdW1tYXJpc2UoZ3JhbmRNLlByb3AgPSBtZWFuKG1lYW4uUHJvcCksIHNlID0gc3RkLmVycm9yKG1lYW4uUHJvcCkpCgojIFBsb3QgbGluZXBsb3Qgd2l0aCBlcnJvciBiYXJzIG9uIHN0ZXAgcG9pbnRzCmJ5R3Vpc2VfcHJvcF9wbG90IDwtIGNvbmRpdGlvbi5tZWFucyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBzdGVwLCB5ID0gZ3JhbmRNLlByb3ApKSArCiAgZ2VvbV9wb2ludChzdGF0PSJpZGVudGl0eSIsIGFlcyhjb2xvdXIgPSBmYWN0b3Ioc3BlYWtlckd1aXNlKSksIGNleD01KSArCiAgZ2VvbV9saW5lKGFlcyhjb2xvdXI9ZmFjdG9yKHNwZWFrZXJHdWlzZSksIGxpbmV0eXBlPWZhY3RvcihzcGVha2VyR3Vpc2UpKSwgbHdkPTEpICsKICBnZW9tX2Vycm9yYmFyKHdpZHRoID0gLjI1LCBhZXMoeW1pbiA9IGdyYW5kTS5Qcm9wLXNlLCB5bWF4ID0gZ3JhbmRNLlByb3Arc2UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBmYWN0b3Ioc3BlYWtlckd1aXNlKSkpICsKICBmYWNldF9ncmlkKHNwZWFrZXJ+dm93ZWwpICsKICBsYWJzKHkgPSAiUHJvcG9ydGlvbiAncmFpc2VkJyByZXNwb25zZSIsIHggPSAiQ29udGludXVtIFN0ZXAgKFVSIHRvIFJTKSIsIGNvbG9yPSJHdWlzZSIsCiAgICAgICBsaW5ldHlwZSA9ICJHdWlzZSIsIHRpdGxlPSJSYWlzaW5nIFBlcmNlcHRpb246IEJ5IEd1aXNlIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwgMSkpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gLTM6MykgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9Z2hpYmxpX3BhbGV0dGUoIlBvbnlvTWVkaXVtIilbYyg2LDQsMyldKSArCiAgZ2dfdGhlbWUoKQpieUd1aXNlX3Byb3BfcGxvdApgYGAKCiMjIyMgUlQgYnkgR3Vpc2UKYGBge3IsIHdhcm5pbmc9RkFMU0V9CiMgR2V0IHN1YmogbWVhbnMgcGVyIGNvbmRpdGlvbgpzdWJqLm1lYW5zIDwtIGNvbmRhdGEudGVzdC5maW5hbCAlPiUgCiAgZ3JvdXBfYnkocGFydGljaXBhbnRJZCwgc3RlcCwgdm93ZWwsIHNwZWFrZXIsIHNwZWFrZXJHdWlzZSkgJT4lCiAgc3VtbWFyaXNlKG1lYW4ucnQgPSBtZWFuKGxvZyhydCkpKQoKIyBHZXQgZ3JvdXAgbWVhbnMgYW5kIHNlIHBlciBjb25kaXRpb24gKGJ5IGF2ZXJhZ2luZyBzcGVha2VyIG1lYW5zKQpjb25kaXRpb24ubWVhbnMgPC0gc3Viai5tZWFucyAlPiUKICBncm91cF9ieShzdGVwLCB2b3dlbCwgc3BlYWtlciwgc3BlYWtlckd1aXNlKSAlPiUKICBzdW1tYXJpc2UoZ3JhbmRNLnJ0ID0gbWVhbihtZWFuLnJ0KSwgc2UgPSBzdGQuZXJyb3IobWVhbi5ydCkpCgojIFBsb3QgbGluZXBsb3Qgd2l0aCBlcnJvciBiYXJzIG9uIHN0ZXAgcG9pbnRzCmJ5R3Vpc2VfcnRfcGxvdCA8LSBjb25kaXRpb24ubWVhbnMgJT4lCiAgZ2dwbG90KGFlcyh4ID0gc3RlcCwgeSA9IGdyYW5kTS5ydCkpICsKICBnZW9tX3BvaW50KHN0YXQ9ImlkZW50aXR5IiwgYWVzKGNvbG91ciA9IGZhY3RvcihzcGVha2VyR3Vpc2UpKSwgY2V4PTUpICsKICBnZW9tX2xpbmUoYWVzKGNvbG91cj1mYWN0b3Ioc3BlYWtlckd1aXNlKSwgbGluZXR5cGU9ZmFjdG9yKHNwZWFrZXJHdWlzZSkpLCBsd2Q9MSkgKwogIGdlb21fZXJyb3JiYXIod2lkdGggPSAuMjUsIGFlcyh5bWluID0gZ3JhbmRNLnJ0LXNlLCB5bWF4ID0gZ3JhbmRNLnJ0K3NlLCBjb2xvdXIgPSBmYWN0b3Ioc3BlYWtlckd1aXNlKSkpICsKICBmYWNldF9ncmlkKHNwZWFrZXJ+dm93ZWwpICsKICBsYWJzKHkgPSAiTG9nIFJlc3BvbnNlIFRpbWUiLCB4ID0gIkNvbnRpbnV1bSBTdGVwIChVUiB0byBSUykiLCBjb2xvcj0iR3Vpc2UiLAogICAgICAgbGluZXR5cGUgPSAiR3Vpc2UiLCB0aXRsZT0iUmVhY3Rpb24gVGltZTogQnkgR3Vpc2UiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1naGlibGlfcGFsZXR0ZSgiUG9ueW9NZWRpdW0iKVtjKDYsNCwzKV0pKwogIGdnX3RoZW1lKCkKYnlHdWlzZV9ydF9wbG90CmBgYAoKIyMjIyBQcm9wUlMgYnkgV29yZApgYGB7cn0KIyBHZXQgc3ViaiBtZWFucyBwZXIgY29uZGl0aW9uCnN1YmoubWVhbnMgPC0gY29uZGF0YS50ZXN0LmZpbmFsICU+JSBmaWx0ZXIoc3BlYWtlcj09IlMzIikgJT4lCiAgZ3JvdXBfYnkocGFydGljaXBhbnRJZCwgc3RlcCwgdm93ZWwsIHNwZWFrZXJHdWlzZSwgc3BlYWtlciwgd29yZCkgJT4lCiAgc3VtbWFyaXNlKG1lYW4uUHJvcCA9IG1lYW4ocmVzcFJTKSkKCiMgR2V0IGdyb3VwIG1lYW5zIGFuZCBzZSBwZXIgY29uZGl0aW9uIChieSBhdmVyYWdpbmcgc3BlYWtlciBtZWFucykKY29uZGl0aW9uLm1lYW5zIDwtIHN1YmoubWVhbnMgJT4lCiAgZ3JvdXBfYnkoc3RlcCwgdm93ZWwsIHNwZWFrZXJHdWlzZSwgc3BlYWtlciwgd29yZCkgJT4lCiAgc3VtbWFyaXNlKGdyYW5kTS5Qcm9wID0gbWVhbihtZWFuLlByb3ApLCBzZSA9IHN0ZC5lcnJvcihtZWFuLlByb3ApKQoKIyBBSQpieVdvcmRfcHJvcF9wbG90IDwtIGNvbmRpdGlvbi5tZWFucyAlPiUgZmlsdGVyKHZvd2VsPT0iQUkiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBzdGVwLCB5ID0gZ3JhbmRNLlByb3ApKSArCiAgZ2VvbV9wb2ludChzdGF0PSJpZGVudGl0eSIsIGFlcyhjb2xvdXIgPSBmYWN0b3Ioc3BlYWtlckd1aXNlKSksIGNleD01LCBhbHBoYT0wLjc1KSArCiAgZ2VvbV9saW5lKGFlcyhjb2xvdXI9ZmFjdG9yKHNwZWFrZXJHdWlzZSksIGxpbmV0eXBlPWZhY3Rvcih3b3JkKSksIGx3ZD0xKSArCiAgZ2VvbV9lcnJvcmJhcih3aWR0aCA9IC4yNSwgYWVzKHltaW4gPSBncmFuZE0uUHJvcC1zZSwgeW1heCA9IGdyYW5kTS5Qcm9wK3NlLCBjb2xvdXIgPSBmYWN0b3Ioc3BlYWtlckd1aXNlKSkpICsKICBmYWNldF9ncmlkKHNwZWFrZXJ+d29yZCkgKwogIGxhYnMoeSA9ICJQcm9wb3J0aW9uICdyYWlzZWQnIHJlc3BvbnNlIiwgeCA9ICJDb250aW51dW0gU3RlcCAoVVIgdG8gUlMpIiwgY29sb3I9Ikd1aXNlIiwKICAgICAgIGxpbmV0eXBlID0gIldvcmQiLCB0aXRsZT0iQUkgUmFpc2luZyBQZXJjZXB0aW9uOiBCeSBXb3JkIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwgMSkpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gLTM6MykgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9Z2hpYmxpX3BhbGV0dGUoIlBvbnlvTWVkaXVtIilbYyg2LDQsMyldKSsKICBnZ190aGVtZSgpCmJ5V29yZF9wcm9wX3Bsb3QKCiMgQVUKYnlXb3JkX3Byb3BfcGxvdCA8LSBjb25kaXRpb24ubWVhbnMgJT4lIGZpbHRlcih2b3dlbD09IkFVIikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gc3RlcCwgeSA9IGdyYW5kTS5Qcm9wKSkgKwogIGdlb21fcG9pbnQoc3RhdD0iaWRlbnRpdHkiLCBhZXMoY29sb3VyID0gZmFjdG9yKHNwZWFrZXJHdWlzZSkpLCBjZXg9NSwgYWxwaGE9MC43NSkgKwogIGdlb21fbGluZShhZXMoY29sb3VyPWZhY3RvcihzcGVha2VyR3Vpc2UpLCBsaW5ldHlwZT1mYWN0b3Iod29yZCkpLCBsd2Q9MSkgKwogIGdlb21fZXJyb3JiYXIod2lkdGggPSAuMjUsIGFlcyh5bWluID0gZ3JhbmRNLlByb3Atc2UsIHltYXggPSBncmFuZE0uUHJvcCtzZSwgY29sb3VyID0gZmFjdG9yKHNwZWFrZXJHdWlzZSkpKSArCiAgZmFjZXRfZ3JpZChzcGVha2VyfndvcmQpICsKICBsYWJzKHkgPSAiUHJvcG9ydGlvbiAncmFpc2VkJyByZXNwb25zZSIsIHggPSAiQ29udGludXVtIFN0ZXAgKFVSIHRvIFJTKSIsIGNvbG9yPSJHdWlzZSIsCiAgICAgICBsaW5ldHlwZSA9ICJXb3JkIiwgdGl0bGU9IkFVIFJhaXNpbmcgUGVyY2VwdGlvbjogQnkgV29yZCIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsIDEpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IC0zOjMpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWdoaWJsaV9wYWxldHRlKCJQb255b01lZGl1bSIpW2MoNiw0LDMpXSkrCiAgZ2dfdGhlbWUoKQpieVdvcmRfcHJvcF9wbG90CgpgYGAKCiMjIyMgUHJvcFJTIGJ5IEluZGl2aWR1YWwKKGFkYXB0ZWQgZnJvbSBDYW50b01lcmdlcnMgcHJvamVjdCkKYGBge3IsIGVjaG89Rn0KIyBNSSBndWlzZQpieVN1YmpfcHJvcF9wbG90IDwtIGNvbmRhdGEudGVzdC5maW5hbCAlPiUgZmlsdGVyKHZvd2VsPT0iQVUiKSAlPiUgZmlsdGVyKGNvbmRpdGlvbklkPT0iY29uZEEiKSAlPiUKICBnZ3Bsb3QoYWVzKHg9c3RlcCwgeT1yZXNwUlMsIGNvbG9yPXNwZWFrZXJHdWlzZSwgbGluZXR5cGU9c3BlYWtlcikpICsKICBnZW9tX3Ntb290aChtZXRob2Q9ImxvZXNzIikgKwogIGZhY2V0X3dyYXAofnBhcnRpY2lwYW50SWQpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBhbHBoYT0wLjUpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAgMC41LCBhbHBoYSA9IDAuNSkgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwgMSkpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gLTM6MykgKwogIGxhYnModGl0bGU9IkFVIFJhaXNpbmcgcGVyY2VwdGlvbjogQnkgUGFydGljaXBhbnQiLCB5PSJQcm9wb3J0aW9uIFJTIHJlc3BvbnNlIiwgY29sb3I9Ikd1aXNlIiwgeD0iIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9Z2hpYmxpX3BhbGV0dGUoIlBvbnlvTWVkaXVtIilbYyg0LDMpXSkrCiAgZ2dfdGhlbWUoKQpieVN1YmpfcHJvcF9wbG90CgojIENOIGd1aXNlCmJ5U3Vial9wcm9wX3Bsb3QgPC0gY29uZGF0YS50ZXN0LmZpbmFsICU+JSBmaWx0ZXIodm93ZWw9PSJBVSIpICU+JSBmaWx0ZXIoY29uZGl0aW9uSWQ9PSJjb25kQyIpICU+JQogIGdncGxvdChhZXMoeD1zdGVwLCB5PXJlc3BSUywgY29sb3I9c3BlYWtlckd1aXNlLCBsaW5ldHlwZT1zcGVha2VyKSkgKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG9lc3MiKSArCiAgZmFjZXRfd3JhcCh+cGFydGljaXBhbnRJZCkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGFscGhhPTAuNSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9ICAwLjUsIGFscGhhID0gMC41KSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLCAxKSkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSAtMzozKSArCiAgbGFicyh0aXRsZT0iQVUgUmFpc2luZyBwZXJjZXB0aW9uOiBCeSBQYXJ0aWNpcGFudCIsIHk9IlByb3BvcnRpb24gUlMgcmVzcG9uc2UiLCBjb2xvcj0iR3Vpc2UiLCB4PSIiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1naGlibGlfcGFsZXR0ZSgiUG9ueW9NZWRpdW0iKVtjKDQsMyldKSsKICBnZ190aGVtZSgpCmJ5U3Vial9wcm9wX3Bsb3QKCiMgQkwgZ3Vpc2UKYnlTdWJqX3Byb3BfcGxvdCA8LSBjb25kYXRhLnRlc3QuZmluYWwgJT4lIGZpbHRlcih2b3dlbD09IkFVIikgJT4lIGZpbHRlcihjb25kaXRpb25JZD09ImNvbmRFIikgJT4lCiAgZ2dwbG90KGFlcyh4PXN0ZXAsIHk9cmVzcFJTLCBjb2xvcj1zcGVha2VyR3Vpc2UsIGxpbmV0eXBlPXNwZWFrZXIpKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsb2VzcyIpICsKICBmYWNldF93cmFwKH5wYXJ0aWNpcGFudElkKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgYWxwaGE9MC41KSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gIDAuNSwgYWxwaGEgPSAwLjUpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsIDEpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IC0zOjMpICsKICBsYWJzKHRpdGxlPSJBVSBSYWlzaW5nIHBlcmNlcHRpb246IEJ5IFBhcnRpY2lwYW50IiwgeT0iUHJvcG9ydGlvbiBSUyByZXNwb25zZSIsIGNvbG9yPSJHdWlzZSIsIHg9IiIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWdoaWJsaV9wYWxldHRlKCJQb255b01lZGl1bSIpW2MoMildKSsKICBnZ190aGVtZSgpCmJ5U3Vial9wcm9wX3Bsb3QKYGBgCgojIC4uLgojIFF1ZXN0aW9ubmFpcmUgRGF0YQojIyBQcmUtUHJvY2VzcyBEYXRhCiMjIyBSZWFkICYgQ2xlYW4gUmVzdWx0cwpUaGUgUXVhbHRyaWNzIG91dHB1dCBpbmNsdWRlcyBhIHRleHQgcmVzcG9uc2UgZmlsZSBhbmQgYSBudW1lcmljYWwgcmVzcG9uc2UgZmlsZS4gQmVjYXVzZSBJIHdhbnQgdG8gdXNlIHRleHQgZm9yIHNvbWUgcXVlc3Rpb25zIChlLmcuIElLMiwgdGhlIHdvcmQgc2VsZWN0aW9uIHF1ZXN0aW9uKSBidXQgbnVtYmVycyBmb3Igb3RoZXIgcXVlc3Rpb25zIChlLmcuIGZhbWlsaWFyaXR5IHNjYWxlIHF1ZXN0aW9ucyksIEkgbmVlZCB0byB3b3JrIHdpdGggYm90aC4KCkkgaGF2ZSBkb3dubG9hZGVkIHRoZSBmaWxlcyBhbmQgcmVuYW1lZCB0aGVtIGFzICdfdGV4dCcgYW5kICdfbnVtIiBmaWxlcy4gU3BlY2lmaWNhbGx5LCBmaWxlIG5hbWVzIGhhdmUgYmVlbiByZW5hbWVkIGZyb20gdGhlIG9yaWdpbmFsIFF1YWx0cmljcyBkb3dubG9hZCBuYW1lIHRvIGBmaW5hbF9sYnFfbnVtLmNzdmAgYW5kIGBmaW5hbF9sYnFfdGV4dC5jc3ZgLgpgYGB7ciwgd2FybmluZz1GfQojIExpc3QgcmVzdWx0cyBmaWxlcyBwZXIgc3ViamVjdApmaWxlbGlzdCA8LSBsaXN0LmZpbGVzKHBhdGg9Ii4vZGF0YS9heGJfMWEvcXVlc3Rpb25uYWlyZS8iLCBwYXR0ZXJuPSIuY3N2IixmdWxsLm5hbWVzPVRSVUUpCgojIFJlYWQgYW5kIENvbmNhdGVuYXRlIHJlc3VsdHMKIyAoMSkgSnVzdCByZWFkIGFuZCBjb25jYXQKI2NvbmRhdGEucmVhZCA8LSBkby5jYWxsKHJiaW5kLCBsYXBwbHkoZmlsZWxpc3QsIHJlYWQuY3N2KSkKCiMgKDIpIFJlYWQsIGNvbmNhdCBhbmQgZXh0cmFjdCBwYXJ0IG9mIGZpbGVuYW1lCnF1ZXNkYXRhLnJlYWQgPC0gZG8uY2FsbChyYmluZCwgbGFwcGx5KGZpbGVsaXN0LCBmdW5jdGlvbih4KSBjYmluZChyZWFkLmNzdih4KSwgZGF0YUZvcm1hdD1zdHJzcGxpdChnc3ViKCIuY3N2IiwiIix4KSwgIl8iKVtbMV1dWzRdKSkpCgojIENoZWNrIHRoYXQgbmV3bHkgZXh0cmFjdGVkIGNvbHVtbnMgYXJlIGNvcnJlY3QgKGBudW1gIG9yIGB0ZXh0YCkKIyBxdWVzZGF0YS5yZWFkJGRhdGFGb3JtYXQKCiMgY29sbmFtZXMocXVlc2RhdGEucmVhZCkKYGBgCgpSZW1vdmUgdGhlIHVubmVjZXNzYXJpbHkgY29sdW1ucyBhbmQgcm93cy4gQWxzbyBleHRyYWN0IHRoZSBxdWVzdGlvbiB0ZXh0IHdoaWxlIHdlJ3JlIGF0IGl0IChiZWZvcmUgcmVtb3ZpbmcgdGhlIHJvd3MpIHNvIHRoYXQgd2UgY2FuIHJlZmVyIHRvIHRoZSBxdWVzdGlvbnMgYXMgbmVjZXNzYXJ5LCBidXQgdGhleSB3b24ndCBiZSBpbiB0aGUgZGF0YSB0byBiZSBhbmFseXNlZC4KYGBge3J9CiMgUmVtb3ZlIG1ldGFkYXRhIGNvbHVtbnMgKGZpcnN0IHNldmVyYWwpCnF1ZXNkYXRhIDwtIHF1ZXNkYXRhLnJlYWQgJT4lIAogIHNlbGVjdCgtYyhTdGFydERhdGUsIEVuZERhdGUsIFN0YXR1cywgSVBBZGRyZXNzLCBQcm9ncmVzcywgRHVyYXRpb24uLmluLnNlY29uZHMuLCBGaW5pc2hlZCwgUmVjb3JkZWREYXRlLCBSZXNwb25zZUlkLCBSZWNpcGllbnRMYXN0TmFtZSwgUmVjaXBpZW50Rmlyc3ROYW1lLCBSZWNpcGllbnRFbWFpbCwgRXh0ZXJuYWxSZWZlcmVuY2UsIExvY2F0aW9uTGF0aXR1ZGUsIExvY2F0aW9uTG9uZ2l0dWRlLCBEaXN0cmlidXRpb25DaGFubmVsLCBVc2VyTGFuZ3VhZ2UsIFBST0xJRklDX1BJRCkpCgojIFF1ZXN0aW9uIHJlZmVyZW5jZSAoaWYgd2FudCB0byBsb29rIGJhY2sgYXQgcXVlc3Rpb24gdGV4dCkKcXVlc3Rpb25zIDwtIHF1ZXNkYXRhICU+JSBzbGljZSgxKQoKIyBSZW1vdmUgdW5lY2Vzc2FyeSBxdWVzdGlvbiBoZWFkZXIgYW5kIHRlc3QgZGF0YSByb3dzICsgYWRkL2ZpeCByZWxldmFudCBpbmZvICsgcmVtb3ZlIGRhdGEgZnJvbSBkcm9wcGVkIHN1YmplY3RzCnF1ZXNkYXRhIDwtIHF1ZXNkYXRhICU+JQogICMgUmVtb3ZlIGlycmVsZXZhbnQgcm93cyBhbmQgcmVtb3ZlZCBkYXRhCiAgc3Vic2V0KHN1YmpJRCAhPSAiUGxlYXNlIGNoZWNrIHRoYXQgeW91ciBQcm9saWZpYyBJRCBpcyBjb3JyZWN0LCB0aGVuIHByZXNzIHRoZSAnbmV4dCcgYnV0dG9uIHRvIGNvbnRpbnVlIHdpdGggdGhlIHN1cnZleS4iICYgc3ViaklEICE9IntcIkltcG9ydElkXCI6XCJRSUQ3OF9URVhUXCJ9IikgJT4lCiAgc3Vic2V0KHN1YmpJRCAhPSAicHJldmlldzEiKSAlPiUKICAKICAjIEZpeCBpbmNvcnJlY3Qgc3ViamVjdCBudW1iZXJzCiAgbXV0YXRlKHN1YmpJRCA9IGdzdWIoIjVhNWE1MDdkNzZkMWM2MDAwMWFiMmFjNzFjNjAwMDFhYjJhYzciLCAiNWE1YTUwN2Q3NmQxYzYwMDAxYWIyYWM3Iiwgc3ViaklEKSkgJT4lCiAgbXV0YXRlKHN1YmpJRCA9IGdzdWIoIjVmNDc0ODc3NDUyODU3MTMwMzE0YzlkMTEiLCAiNWY0NzQ4Nzc0NTI4NTcxMzAzMTRjOWQxIiwgc3ViaklEKSkgJT4lCiAgZHJvcGxldmVscygpICU+JQoKICAjIE1lcmdlIHdpdGggcGVyY2VwdGlvbiBkYXRhIChmb3IgY29udmVuaWVuY2UsIHVzZXMgdGhlIG1pbmltYWwgZGF0YWZyYW1lIGBjb25kYXRhLnRvbmVzYCkKICAjIyBBZGRzIHN1YmplY3QgYW5kIGNvbmRpdGlvbiBpbmZvICsgYXV0b21hdGljYWxseSBkcm9wcyBzdWJqZWN0cyB0aGF0IHdlcmUgc2NyZWVuZWQgb3V0IGJhc2VkIG9uIHBlcmNlcHRpb24gZXhwZXJpbWVudCBwZXJmb3JtYW5jZS9yZXR1cm5zCiAgcmVuYW1lKHBhcnRpY2lwYW50SWQgPSBzdWJqSUQpICU+JQogIG1lcmdlKC4sIGNvbmRhdGEudG9uZXMpICU+JQogIG11dGF0ZShndWlzZUNvbWJpbmF0aW9uID0gY2FzZV93aGVuKGNvbmRpdGlvbklkID09ICJjb25kQSIgfCBjb25kaXRpb25JZCA9PSAiY29uZEIiIH4gIm1hdGNoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmRpdGlvbklkID09ICJjb25kQyIgfCBjb25kaXRpb25JZCA9PSAiY29uZEQiIH4gIm1pc21hdGNoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmRpdGlvbklkID09ICJjb25kRSIgfCBjb25kaXRpb25JZCA9PSAiY29uZEYiIH4gImJhc2VsaW5lIikpICU+JQogIG11dGF0ZShzcGVha2VyT3JkZXIgPSBjYXNlX3doZW4oY29uZGl0aW9uSWQgPT0gImNvbmRBIiB8IGNvbmRpdGlvbklkID09ICJjb25kQyIgfCBjb25kaXRpb25JZCA9PSAiY29uZEUiIH4gIlMzLVM5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmRpdGlvbklkID09ICJjb25kQiIgfCBjb25kaXRpb25JZCA9PSAiY29uZEQiIHwgY29uZGl0aW9uSWQgPT0gImNvbmRGIiB+ICJTOS1TMyIpKSAlPiUKICBkcm9wbGV2ZWxzKCkKCmBgYAoKIyMjIyBRdWVzdGlvbiBXb3JkaW5nCkhlcmUncyB0aGUgdGFibGUgb2YgdGhlIHF1ZXN0aW9uIHRhZ3MsIG51bWJlcnMgYW5kIHRleHQuIFRoaXMgaW50ZXJhY3RpdmUgdGFibGUgYWxsb3dzIGZvciBzb3J0aW5nIGFuZCBzZWFyY2hpbmchIFdlIGNhbiB1c2UgdGhpcyB0byBjaGVjayB0aGUgZXhhY3Qgd29yZGluZyBvZiB0aGUgcXVlc3Rpb25z4oCUYWxsIG9mIHRoZW0gYXMgdGhleSB3ZXJlIHNob3duIHRvIHRoZSBwYXJ0aWNpcGFudC4KCmBgYHtyLCBldmFsPUYsIHJlc3VsdHM9J2FzaXMnfQojIFByaW50IHF1ZXN0aW9ucyBmb3IgcmVmZXJlbmNlCkRUOjpkYXRhdGFibGUocXVlc3Rpb25zLCAKICAgICAgICAgICAgICBvcHRpb25zPWxpc3Qoc2Nyb2xsWCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGF1dG9XaWR0aCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbkRlZnMgPSBsaXN0KGxpc3Qod2lkdGggPSAnMjAwcHgnLCB0YXJnZXRzID0gIl9hbGwiKSkpKQpgYGAKCiMjIyBQcm9jZXNzIERlbW9ncmFwaGljIEluZm8KYGBge3J9CiMgU3Vic2V0IHRvIGRlbW9ncmFwaGljIHF1ZXN0aW9uIGNvbHVtbnMKcXVlc2RhdGEuZGVtbyA8LSBxdWVzZGF0YSAlPiUgZmlsdGVyKGRhdGFGb3JtYXQgPT0gInRleHQiKSAlPiUKICBzZWxlY3QoY29uZGl0aW9uSWQsIHBhcnRpY2lwYW50SWQsIGd1aXNlQ29tYmluYXRpb24sIHNwZWFrZXJPcmRlciwgCiAgICAgICAgIEFnZSwgR2VuZGVyLCBFdGhuaWNpdHksIFNwSERpc29yZGVyLCBTcEhEaXNvcmRlcl8yX1RFWFQsIERlZ3JlZSwgTGluZ0V4cCwgRmlyc3RMYW5nLCAKICAgICAgICAgTG9jMV8xOkxvYzZfNCkgJT4lCiAgCiAgIyBGaXggc3BlbGxpbmcgZXJyb3JzIGFuZCB2YXJpYXRpb24gb24gZGVtb2dyYXBoaWMgcXVlc3Rpb25zCiAgbXV0YXRlX2F0KHZhcnMoLWNvbmRpdGlvbklkLCAtc3BlYWtlck9yZGVyKSx0b2xvd2VyKSAlPiUKICBtdXRhdGVfaWYoaXMuY2hhcmFjdGVyLCBzdHJfdHJpbSkKCiMgQ2hlY2sgZGF0YQpxdWVzZGF0YS5kZW1vCgojIFN1bW1hcnkKIyBzdW1tYXJ5KHF1ZXNkYXRhLmRlbW8pCmBgYAoKIyMjIyBDaGVjayBWYWx1ZXMKYGBge3J9CiMgUXVpY2sgY2hlY2sgdmlhIHRhYmxlCnF1ZXMuZGVtby5zdW0gPC0gcXVlc2RhdGEuZGVtbyAlPiUgIHNlbGVjdChjb25kaXRpb25JZCwgQWdlLCBHZW5kZXIsIEV0aG5pY2l0eSwgTG9jMV80KQpgYGAKCmBgYHtyfQp3aXRoKHF1ZXNkYXRhLmRlbW8sIHVuaXF1ZShHZW5kZXIpKQpgYGAKCgpgYGB7cn0Kd2l0aChxdWVzZGF0YS5kZW1vLCB1bmlxdWUoTG9jMV80KSkKYGBgCgpgYGB7cn0Kd2l0aChxdWVzZGF0YS5kZW1vLCB1bmlxdWUoRXRobmljaXR5KSkKYGBgCgojIyMjIENsZWFuIEZyZWUgUmVzcG9uc2VzCmBgYHtyfQpxdWVzZGF0YS5kZW1vIDwtIHF1ZXNkYXRhLmRlbW8gJT4lCiAgCiAgbXV0YXRlKEdlbmRlciA9IG1nc3ViKEdlbmRlciwgYygid29tYW4uKnwuKmZlbWFsLioiLCAibWFsZXxjaXMgbWFsZSIsICJub24tYmluYXJ5fG5vbiBiaW5hcnl8bm9uYmluYXJ5IiksIGMoImYiLCAibSIsICJuYiIpKSkgJT4lCiAgCiAgbXV0YXRlX2F0KHZhcnMoc3RhcnRzX3dpdGgoIkxvYyIpICYgZW5kc193aXRoKCJfNCIpKSwgfiBtZ3N1YigueCwgYygibWljaGlnLip8bWlbLywgXS4qIiksIGMoIm1pIikpKSAlPiUKICAKICBtdXRhdGUoRXRobmljaXR5ID0gbWdzdWIoRXRobmljaXR5LCBjKCJjYXVjYXNpYW58Y2F1Y2FzaW9ufGNhdWFjYXNpYW58YW1lcmljYW58d3JpdGV8ZXVyb3BlYW58ZHV0Y2guKiIsImFmcmljYW4gYW1lcmljYW58YWZyaWNhbi1hbWVyaWNhbiIsICJtaWRkbGUgZWFzdC4qIiwgImxhdGlubyIsICJiaXJhY2lhbC4qfG11bHRpLip8bWl4ZWQiKSwgYygid2hpdGUiLCAiYmxhY2siLCAibWlkZGxlLWVhc3Rlcm4iLCAiaGlzcGFuaWMiLCAibXVsdGlyYWNpYWwiKSkpICU+JQogIG11dGF0ZShFdGhuaWNpdHkgPSBtZ3N1YihFdGhuaWNpdHksIGMoImZpbGlwaW5vL3doaXRlIiwid2hpdGUvaGlzcGFuaWMiLCAiYW0uIGluZGlhbiIpLCBjKCJtdWx0aXJhY2lhbCIsIm11bHRpcmFjaWFsIiwgIm5hdGl2ZSIpLCBmaXhlZD1UUlVFKSkgJT4lCiAgbXV0YXRlKEV0aG5pY2l0eSA9IG1nc3ViKEV0aG5pY2l0eSwgYygiLip3aGl0ZS4qIiwgImJsYWNrLioiLCAiLiphc2lhbi4qIiksIGMoIndoaXRlIiwgImJsYWNrIiwgImFzaWFuIikpKSAlPiUKICAKICAjIENoYW5nZSB2ZWN0b3IgY2xhc3NlcyBmcm9tIGNoYXJhY3RlciBjbGFzcwogIG11dGF0ZV9hdCh2YXJzKEFnZSksIGFzLm51bWVyaWMpICU+JQogIAogICMgU2VsZWN0CiAgc2VsZWN0KGNvbmRpdGlvbklkLCBwYXJ0aWNpcGFudElkLCBldmVyeXRoaW5nKCkpCiAgCnF1ZXNkYXRhLmRlbW8KCmBgYAoKIyMjIyBEZXNjcmlwdGl2ZSBTdGF0cwpgYGB7cn0KIyBFdGhuaWNpdHkgQ291bnRzCnF1ZXNkYXRhLmRlbW8gJT4lIGdyb3VwX2J5KEV0aG5pY2l0eSkgJT4lIGNvdW50KCkgCgpxdWVzZGF0YS5kZW1vICU+JSBncm91cF9ieShFdGhuaWNpdHksIGNvbmRpdGlvbklkKSAlPiUgY291bnQoKSAlPiUgcGl2b3Rfd2lkZXIoRXRobmljaXR5LCBuYW1lc19mcm9tID0gY29uZGl0aW9uSWQsIHZhbHVlc19mcm9tPW4pCgpgYGAKYGBge3J9CiMgR2VuZGVyIENvdW50cwpxdWVzZGF0YS5kZW1vICU+JSBncm91cF9ieShHZW5kZXIpICU+JSBjb3VudCgpCgpxdWVzZGF0YS5kZW1vICU+JSBncm91cF9ieShHZW5kZXIsIGNvbmRpdGlvbklkKSAlPiUgY291bnQoKSAlPiUgcGl2b3Rfd2lkZXIoR2VuZGVyLCBuYW1lc19mcm9tID0gY29uZGl0aW9uSWQsIHZhbHVlc19mcm9tPW4pCgpgYGAKCmBgYHtyfQojIEFnZQpxdWVzZGF0YS5kZW1vICU+JSBzdW1tYXJpc2Uobj1sZW5ndGgoY29uZGl0aW9uSWQpLCBtaW5BZ2UgPSBtaW4oQWdlKSwgbWF4QWdlID0gbWF4KEFnZSksIG1lYW5BZ2UgPSBtZWFuKEFnZSksIHNkQWdlID0gc2QoQWdlKSkKCnF1ZXNkYXRhLmRlbW8gJT4lIGdyb3VwX2J5KGNvbmRpdGlvbklkKSAlPiUKICBzdW1tYXJpc2Uobj1sZW5ndGgoY29uZGl0aW9uSWQpLCBtaW5BZ2UgPSBtaW4oQWdlKSwgbWF4QWdlID0gbWF4KEFnZSksIG1lYW5BZ2UgPSBtZWFuKEFnZSksIHNkQWdlID0gc2QoQWdlKSkgJT4lIHVuZ3JvdXAoKQoKYGBgCgojIyMjIExvY2F0aW9ucyBMaXN0ICh1bmRlciBkZXYpCmBgYHtyfQpxdWVzZGF0YS5sb2MgPC0gcXVlc2RhdGEuZGVtbyAlPiUgc2VsZWN0KHBhcnRpY2lwYW50SWQsIHN0YXJ0c193aXRoKCJMb2MiKSkKcXVlc2RhdGEubG9jCgpsb2MuY29kZSA8LSBkYXRhLmZyYW1lKExvYyA9IHVuaXF1ZSgocXVlc2RhdGEubG9jJExvYzFfMykpKSAlPiUKICByYmluZChkYXRhLmZyYW1lKExvYyA9IHVuaXF1ZSgocXVlc2RhdGEubG9jJExvYzJfMykpKSkgJT4lCiAgcmJpbmQoZGF0YS5mcmFtZShMb2MgPSB1bmlxdWUoKHF1ZXNkYXRhLmxvYyRMb2MzXzMpKSkpICU+JQogIHJiaW5kKGRhdGEuZnJhbWUoTG9jID0gdW5pcXVlKChxdWVzZGF0YS5sb2MkTG9jNF8zKSkpKSAlPiUKICByYmluZChkYXRhLmZyYW1lKExvYyA9IHVuaXF1ZSgocXVlc2RhdGEubG9jJExvYzVfMykpKSkgJT4lCiAgcmJpbmQoZGF0YS5mcmFtZShMb2MgPSB1bmlxdWUoKHF1ZXNkYXRhLmxvYyRMb2M2XzMpKSkpICU+JQogIHVuaXF1ZSgpCmxvYy5jb2RlCmBgYAoKCiMjIyBQcm9jZXNzIFRleHQgUmVzcG9uc2VzCmBgYHtyIGxicWRhdGEtdGV4dH0KIyBTdWJzZXQgZGF0YSB0byB0ZXh0IGZvcm1hdApxdWVzZGF0YS50ZXh0IDwtIHF1ZXNkYXRhICU+JSBmaWx0ZXIoZGF0YUZvcm1hdCA9PSAidGV4dCIpICU+JQogIHNlbGVjdChwYXJ0aWNpcGFudElkLCBjb25kaXRpb25JZCwgZ3Vpc2VDb21iaW5hdGlvbiwgc3BlYWtlck9yZGVyLCBldmVyeXRoaW5nKCkpICU+JQogIHNlbGVjdCgtYyhBZ2UsIEdlbmRlciwgRXRobmljaXR5LCBTcEhEaXNvcmRlciwgU3BIRGlzb3JkZXJfMl9URVhULCBEZWdyZWUsIExpbmdFeHAsIEZpcnN0TGFuZywgCiAgICAgICAgIExvYzFfMTpMb2M2XzQsIGV4cFB1cnBvc2UpKSAlPiUKICBtdXRhdGVfaWYoaXMuY2hhcmFjdGVyLCBhcy5mYWN0b3IpCgpxdWVzZGF0YS50ZXh0LnN1YiA8LSBxdWVzZGF0YS50ZXh0ICU+JSAKICBzZWxlY3QoLXN0YXJ0c193aXRoKCJRIiksIC1TQzAsIC10b25lc0NvcnJlY3QpICU+JQogIGRyb3BsZXZlbHMoKQpxdWVzZGF0YS50ZXh0LnN1YgpgYGAKCiMjIyMgSUsyOiBXb3JkIFNlbGVjdGlvbiBRdWVzdGlvbgpJSzIgKEltcGxpY2l0IEtub3dsZWRnZSBRMikgcmVmZXJzIHRvIHRoZSBxdWVzdGlvbiB3aGVyZSBzdWJqZWN0cyBzZWxlY3QgYWxsIHRoZSB3b3JkcyB0aGV5IHRoaW5rIENhbmFkaWFucyBhbmQgTWljaGlnYW5kZXJzIHdvdWxkIHByb25vdW5jZSBkaWZmZXJlbnRseSAoIldoaWNoIG9mIHRoZSBmb2xsb3dpbmcgd29yZHMsIGlmIGFueSwgZG8geW91IHRoaW5rIHdvdWxkIGJlIHByb25vdW5jZWQgZGlmZmVyZW50bHkgYnkgc29tZW9uZSBmcm9tIENhbmFkYSwgYXMgb3Bwb3NlZCB0byBzb21lb25lIGZyb20gTWljaGlnYW4/IFBsZWFzZSBzZWxlY3QgYWxsIHRoYXQgYXBwbHkuIikuIFRoZSBxdWVzdGlvbiBpbmNsdWRlcyAzMCB3b3JkcywgNSBvZiB3aGljaCBhcmUgdGFyZ2V0IC9hdS8gd29yZHMgYW5kIDUgb2Ygd2hpY2ggYXJlIHRhcmdldCAvYWkvIHdvcmRzLgoKV2Ugd2FudCB0byBnbyBmcm9tIHRoZSByYXcgZGF0YSwgdGhlIHNlbGVjdGVkIHdvcmRzLCB0byB0aGUgbnVtYmVyIG9mIHRhcmdldCB3b3JkcyAoL2F1LyBhbmQgL2FpLyByYWlzaW5nIHdvcmRzKSBzZWxlY3RlZC4gVGhlIHJlc3BvbnNlIGZvcm1hdCBpcyB3b3JkcyBzZXBhcmF0ZWQgYnkgY29tbWFzIGluIG9uZSBjZWxsLiBTbywgd2UgbmVlZCB0byBzZXBhcmF0ZSB0aGUgc3RyaW5ncyBpbnRvIHNlcGFyYXRlIHdvcmRzLCBjaGVjayB3aGV0aGVyIGVhY2ggdGFyZ2V0IHdvcmQgb2NjdXJlZCwgdGhlbiB0YWJ1bGF0ZSB0aGUgc2NvcmVzLiBBIHNpbXBsZSBzZWFyY2ggZm9yIHdvcmQgc3RyaW5ncyB3b24ndCB3b3JrLCBiZWNhdXNlIHNvbWUgd29yZHMgKGUuZy4gX291dF8pIGFyZSBzdWJzdHJpbmdzIG9mIG90aGVyIHdvcmRzIChlLmcuIF9hYm91dF8pLiAKCk15IHNvbHV0aW9uIHdhcyB0byBmaXJzdCBzZXBhcmF0ZSB0aGUgc2luZ2xlIGNvbHVtbiBieSBjb21tYXMgaW50byBtdWx0aXBsZSBjb2x1bW5zLCBvbmUgcGVyIHdvcmQuIFRvIGNoZWNrIHdoZXRoZXIgdGhlIHdvcmQgd2FzIGEgcmVzcG9uc2UsIEkgaW1wbGVtZW50IGEgY291bnQgb2YgMSBpbiBhIG5ldyBjb2x1bW4gaWYgYSBzZWFyY2ggZnVuY3Rpb24gZmluZHMgdGhlIHRhcmdldCBzdHJpbmcgaW4gYSByb3cuIFRoaXMgaXMgZG9uZSBmb3IgZWFjaCB0YXJnZXQgd29yZC4gRmluYWxseSwgSSBzdW0gdGhlIGNvdW50IGNvbHVtbnMgZm9yIC9haS8gYW5kIC9hdS8gc2VwYXJhdGVseSB0byBnZXQgYSBzY29yZSBvdXQgb2YgNS4KCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQojIElLMjogQ2FuIFdvcmQgU2VsZWN0aW9uIHF1ZXN0aW9uCgojIFNlbGVjdCBvbmx5IElLMiBxdWVzdGlvbiArIGNyZWF0ZSBjb3BpZWQgY29sdW1uIG9mIFdvcmRzIChmb3IgbmV4dCBzdGVwKQppazIgPC0gc2VsZWN0KHF1ZXNkYXRhLnRleHQuc3ViLCBwYXJ0aWNpcGFudElkLCBJSzIuQ2FuV29yZHMpCmlrMiA8LSBtdXRhdGUoaWsyLCBXb3JkcyA9IElLMi5DYW5Xb3JkcykKCiMgU2VwYXJhdGUgV29yZHMgaW50byBjb2x1bW5zIChieSBjb21tYSkgKyBjcmVhdGUgbmV3IGNvbHVtbnMgb2Ygd29yZCBpbiBsaXN0IHBlciByb3cKIyBOdW1iZXIgb2YgY29sdW1ucyBtdXN0IGJlIHRoZSBzYW1lIGZvciBldmVyeSByb3csIHNvIGZpbmQgdGhlIG1heCBudW1iZXIgb2Ygd29yZHMgc2VsZWN0ZWQgYnkgYW55IHN1YmplY3QgKDIzIGhlcmUpCiMgRWFjaCBzdWJqZWN0IHdpbGwgaGF2ZSAyMyBjb2x1bW5zLCBvbmUgd29yZCBwZXIgY29sdW1uIChXb3JkXzEsIFdvcmRfMi4uLikgdW50aWwgbm8gbW9yZSB3b3JkcyAoTkEgaWYgbm8gd29yZCkKaWsyIDwtIHNlcGFyYXRlKGlrMiwgIldvcmRzIiwgcGFzdGUoIldvcmQiLCAxOjMwLCBzZXA9Il8iKSwgc2VwPSIsIiwgZXh0cmE9ImRyb3AiKQoKIyBJZGVudGlmeSB0YXJnZXQgd29yZHMgaW4gZWFjaCBzdWJqZWN0cycgcmVzcG9uc2VzCiMgQ291bnQgMSBpZiB3b3JkIGV4aXN0cyBpbiByb3c7IDAgaWYgbm9uZQojIC9hdS8gdGFyZ2V0cwppazIgPC0gbXV0YXRlKGlrMiwgSUsyLmF1Lm91dCA9IGFzLmludGVnZXIoYXBwbHkoaWsyLCAxLCBmdW5jdGlvbih4KSBhbnkoeCAlaW4lICJvdXQiKSkpLAogICAgICAgICAgICAgIElLMi5hdS5hYm91dCA9IGFzLmludGVnZXIoZ3JlcGwoJ2Fib3V0JyxJSzIuQ2FuV29yZHMpKSwKICAgICAgICAgICAgICBJSzIuYXUuZGV2b3V0ID0gYXMuaW50ZWdlcihncmVwbCgnZGV2b3V0JyxJSzIuQ2FuV29yZHMpKSwKICAgICAgICAgICAgICBJSzIuYXUuaG91c2UgPSBhcy5pbnRlZ2VyKGdyZXBsKCdob3VzZScsSUsyLkNhbldvcmRzKSksCiAgICAgICAgICAgICAgSUsyLmF1LnBvdWNoID0gYXMuaW50ZWdlcihncmVwbCgncG91Y2gnLElLMi5DYW5Xb3JkcykpKQoKIyAvYWkvIHRhcmdldHMKaWsyIDwtIG11dGF0ZShpazIsIElLMi5haS5saWtlID0gYXMuaW50ZWdlcihhcHBseShpazIsIDEsIGZ1bmN0aW9uKHgpIGFueSh4ICVpbiUgImxpa2UiKSkpLAogICAgICAgICAgICAgIElLMi5haS5yaWdodCA9IGFzLmludGVnZXIoYXBwbHkoaWsyLCAxLCBmdW5jdGlvbih4KSBhbnkoeCAlaW4lICJyaWdodCIpKSksCiAgICAgICAgICAgICAgSUsyLmFpLm1pZ2h0ID0gYXMuaW50ZWdlcihhcHBseShpazIsIDEsIGZ1bmN0aW9uKHgpIGFueSh4ICVpbiUgIm1pZ2h0IikpKSwKICAgICAgICAgICAgICBJSzIuYWkudW5pdGUgPSBhcy5pbnRlZ2VyKGdyZXBsKCd1bml0ZScsSUsyLkNhbldvcmRzKSksCiAgICAgICAgICAgICAgSUsyLmFpLnJpcGUgPSBhcy5pbnRlZ2VyKGFwcGx5KGlrMiwgMSwgZnVuY3Rpb24oeCkgYW55KHggJWluJSAicmlwZSIpKSkpCgojIFN1bSBvZiB0YXJnZXRzIHNlbGVjdGVkIGZvciAvYXUvIGFuZCAvYWkvCmlrMiA8LSBtdXRhdGUoaWsyLCBJSzIuYXUgPSByb3dTdW1zKHNlbGVjdChpazIsIElLMi5hdS5vdXQ6SUsyLmF1LnBvdWNoKSksCiAgICAgICAgICAgICAgSUsyLmFpID0gcm93U3VtcyhzZWxlY3QoaWsyLCBJSzIuYWkubGlrZTpJSzIuYWkucmlwZSkpKQoKIyBIZXJlIGFyZSB0d28gdmVyc2lvbnMgb2YgdGhlIGRhdGEKIyAuLi53aXRoIHNjb3JlIGZvciBlYWNoIHRhcmdldCB3b3JkICsgc3VtIG9mIC9hdS8gYW5kIC9haS8gdGFyZ2V0cyBzZWxlY3RlZAppazIudmFsdWVzIDwtIHNlbGVjdChpazIsIHBhcnRpY2lwYW50SWQsIElLMi5hdSwgSUsyLmFpLCBJSzIuYXUub3V0OklLMi5haS5yaXBlKQoKIyAuLi53aXRoIG9ubHkgc3VtIG9mIC9hdS8gYW5kIC9haS8gdGFyZ2V0cyBzZWxlY3RlZAppazIuc3VtIDwtIHNlbGVjdChpazIsIHBhcnRpY2lwYW50SWQsIElLMi5hdTpJSzIuYWkpCgpgYGAKCgoKIyMjIFByb2Nlc3MgTnVtIFJlc3BvbnNlcwpBIGZldyBjYXNlcyB3aGVyZSBwYXJ0aWNpcGFudHMgZG8gbm90IHJlc3BvbmQgdG8gYSBxdWVzdGlvbiBiZWNhdXNlIHRoZSBhbnN3ZXIgaXMgJ25vJyByZXN1bHRzIGluIGFuICdOQScgZW50cnkuIFRoZXNlICdOQSdzIGZvciBzcGVjaWZpYyBjb2x1bW5zIGFyZSBhZGp1c3RlZCAibWFudWFsbHkiIHRvIHRoZSBjb3JyZWN0IHZhbHVlLiAKCmBgYHtyIGxicWRhdGEtbnVtfQojIFN1YnNldCBkYXRhIHRvIG51bSBmb3JtYXQKcXVlc2RhdGEubnVtIDwtIHF1ZXNkYXRhICU+JSBzdWJzZXQoZGF0YUZvcm1hdCA9PSAibnVtIikgJT4lCiAgc2VsZWN0KHBhcnRpY2lwYW50SWQsIGNvbmRpdGlvbklkLCBndWlzZUNvbWJpbmF0aW9uLCBzcGVha2VyT3JkZXIsIGV2ZXJ5dGhpbmcoKSkgJT4lCiAgc2VsZWN0KC1jKEFnZSwgR2VuZGVyLCBFdGhuaWNpdHksIFNwSERpc29yZGVyLCBTcEhEaXNvcmRlcl8yX1RFWFQsIERlZ3JlZSwgTGluZ0V4cCwgRmlyc3RMYW5nLCAKICAgICAgICAgTG9jMV8xOkxvYzZfNCwgZXhwUHVycG9zZSkpICU+JQogIHJlbmFtZShFUS5yYXdzID0gU0MwKSAlPiUKICBtdXRhdGVfYXQodmFycyhwYXJ0aWNpcGFudElkOnNwZWFrZXJPcmRlciksIGFzLmZhY3RvcikgJT4lCiAgbXV0YXRlX2lmKH4gYWxsKGdyZXBsKCdeXFxkKyQnLCAueCkpLCBhcy5udW1lcmljKQoKIyMgRnVydGhlciBhZGp1c3RtZW50cwpxdWVzZGF0YS5udW0uc3ViIDwtIHF1ZXNkYXRhLm51bSAlPiUKICAjIENvbnZlcnQgY29sdW1ucyB0byBudW1lcmljLCBsZWF2aW5nIG5vbi1udW1lcmljIGNvbHVtbnMgYXMgTkEKICBtdXRhdGVfaWYoaXMuY2hhcmFjdGVyLCBhcy5udW1lcmljKSAlPiUKICAjIFJlbW92ZSBjb2x1bW5zIHRoYXQgYXJlIGFsbCBOQSAoc3BlY2lmaWNhbGx5LCBpZiBTdW0gb2YgdGhhdCBjb2x1bW4ncyBOQXMgaXMgTk9UIGVxdWFsIHRvIHRoZSBudW1iZXIgb2Ygcm93cywgc2VsZWN0ICkKICBzZWxlY3RfaWYoY29sU3Vtcyhpcy5uYSguKSkgIT0gbnJvdyguKSkgJT4lCiAgIyBSZW1vdmUgY29sdW1ucyBvZiBjZXJ0YWluIHR5cGVzIG9mIHF1ZXN0aW9ucyBvciBzcGVjaWZpYyBxdWVzdGlvbiBudW1iZXIKICBzZWxlY3QoLXN0YXJ0c193aXRoKCJRIiksIC1zdGFydHNfd2l0aCgiTGFuZyIpLCAtc3RhcnRzX3dpdGgoIklLMiIpLCAtc3RhcnRzX3dpdGgoIk1FMSIpLCAtZW5kc193aXRoKCJURVhUIikpICU+JQoKICAjIEFkanVzdCB2YWx1ZXMgb2YgTkEgKGZvciBjYXNlcyB3aGVyZSB0aGV5IGNhbiBiZSBpbnRlcnByZXRlZCBhcyBhICdubycgb3IgJ25ldmVyJykKICBtdXRhdGUoVHJhdmVsLk5FX1Zpc2l0cyA9IGNvYWxlc2NlKFRyYXZlbC5ORV9WaXNpdHMsIDEpLCBUcmF2ZWwuU19WaXNpdHMgPSBjb2FsZXNjZShUcmF2ZWwuU19WaXNpdHMsIDEpLAogICAgICAgICBUcmF2ZWwuV19WaXNpdHMgPSBjb2FsZXNjZShUcmF2ZWwuV19WaXNpdHMsIDEpLCBUcmF2ZWwuQ2FuX1Zpc2l0cyA9IGNvYWxlc2NlKFRyYXZlbC5DYW5fVmlzaXRzLCAxKSwKICAgICAgICAgVHJhdmVsLk5FX1RpbWUgPSBjb2FsZXNjZShUcmF2ZWwuTkVfVGltZSwgMSksIFRyYXZlbC5TX1RpbWUgPSBjb2FsZXNjZShUcmF2ZWwuU19UaW1lLCAxKSwKICAgICAgICAgVHJhdmVsLldfVGltZSA9IGNvYWxlc2NlKFRyYXZlbC5XX1RpbWUsIDEpLCBUcmF2ZWwuQ2FuX1RpbWUgPSBjb2FsZXNjZShUcmF2ZWwuQ2FuX1RpbWUsIDEpLAogICAgICAgICBQRTEuUmVsYXRpdmVzID0gY29hbGVzY2UoUEUxLlJlbGF0aXZlcywgMiksIFBFMS5DbG9zZUZhbUZyaWVuZHMgPSBjb2FsZXNjZShQRTEuQ2xvc2VGYW1GcmllbmRzLCAyKSwKICAgICAgICAgRUszLkNhbkFJLkRpZmYgPSBjb2FsZXNjZShFSzMuQ2FuQUkuRGlmZiwgMiksIEVLNC5DYW5BVS5EaWZmID0gY29hbGVzY2UoRUs0LkNhbkFVLkRpZmYsIDIpLAogICAgICAgICBNRTMuU291cmNlcy5PdGhlck1lZGlhXzEgPSBjb2FsZXNjZShNRTMuU291cmNlcy5PdGhlck1lZGlhXzEsIDEpLCAKICAgICAgICAgTUUzLlNvdXJjZXMuT3RoZXJfMSA9IGNvYWxlc2NlKE1FMy5Tb3VyY2VzLk90aGVyXzEsIDEpLAogICAgICAgICBNRTMuU291cmNlcy5OZXdzXzEgPSBjb2FsZXNjZShNRTMuU291cmNlcy5OZXdzXzEsIDEpKSAlPiUKICBkcm9wbGV2ZWxzKCkKCnF1ZXNkYXRhLm51bS5zdWIKYGBgCgojIyMgRmluYWxpemUgQ2xlYW5lZCBSZXN1bHRzCgpgYGB7ciwgd2FybmluZz1GfQojIFNlbGVjdCBhbmQgTWVyZ2Ugb25seSByZWxhdmFudCBudW1lcmljYWwgY29sdW1ucyBvZiBkYXRhIGZvciBQQ0EgYW5hbHlzaXMKcXVlc2RhdGEuY2xlYW4gPC0gcXVlc2RhdGEuZGVtbyAlPiUKICBzZWxlY3QocGFydGljaXBhbnRJZCwgY29uZGl0aW9uSWQsIGd1aXNlQ29tYmluYXRpb24sIHNwZWFrZXJPcmRlciwgQWdlLCBHZW5kZXIsIEV0aG5pY2l0eSkgJT4lCiAgbWVyZ2UoLiwgaWsyLnZhbHVlcykgJT4lCiAgbWVyZ2UoLiwgcXVlc2RhdGEubnVtLnN1YikgJT4lCiAgZHJvcGxldmVscygpCgojIHF1ZXNkYXRhLmZpbmFsCnF1ZXNkYXRhLmNsZWFuCmBgYAoKIyMgQW5hbHl6ZSBEYXRhCgojIyMgUENBOiBBd2FyZW5lc3MgJiBFeHBlcmllbmNlCgpgYGB7cn0KIyBDaGVjayBjb3JyZWxhdGlvbnMsIHdoaWNoIG1vdGl2YXRlIHRoZSB1c2Ugb2YgUENBIHRvIHJlZHVjZSBkaW1lbnNpb25hbGl0eQp3aXRoKHF1ZXNkYXRhLmNsZWFuLCBjb3IudGVzdChJSzIuYWksIElLMi5hdSkpCgojIFRlc3QgY29ycmVsYXRpb25zIG9mIHNpbWlsYXIgcXVlc3Rpb25zCndpdGgocXVlc2RhdGEuY2xlYW4sIGNvci50ZXN0KFRyYXZlbC5DYW5fVmlzaXRzLCBUcmF2ZWwuQ2FuX1RpbWUpKQp3aXRoKHF1ZXNkYXRhLmNsZWFuLCBjb3IudGVzdChTRTEuRmFtLm9vdF8xLCBTRTIuRnJlcS5PdmVyYWxsXzEpKQp3aXRoKHF1ZXNkYXRhLmNsZWFuLCBjb3IudGVzdChTRTIuRnJlcS5PdmVyYWxsXzEsIFNFMi5GcmVxLlJlY2VudF8xKSkKd2l0aChxdWVzZGF0YS5jbGVhbiwgY29yLnRlc3QoU0UyLkZyZXEuT3ZlcmFsbF8xLCBTRTIuRnJlcS5DaGlsZF8xKSkKd2l0aChxdWVzZGF0YS5jbGVhbiwgY29yLnRlc3QoU0UyLkZyZXEuUmVjZW50XzEsIFNFMi5GcmVxLkNoaWxkXzEpKQpgYGAKCiMjIyMgUnVuIFBDQQoKUGFja2FnZXMgcmVxdWlyZWQgZm9yIHRoaXMgUENBOgoqIGBQQ0FgIGNvbW1hbmQgZnJvbSBgRmFjdG9NaW5lUmAgbGlicmFyeSAoc2VlIGluZGV4IGZvciBtb3JlIGluZm8pCiogYHBhcmFuYCBjb21tYW5kIGZyb20gYHBhcmFuYCBsaWJyYXJ5CiogYFZhcmltYXhgIGNvbW1hbmQgZnJvbSBgR1BBcm90YXRpb25zYCBsaWJyYXJ5IChodHRwczovL3N0YXRzLnN0YWNrZXhjaGFuZ2UuY29tL3F1ZXN0aW9ucy81OTIxMy9ob3ctdG8tY29tcHV0ZS12YXJpbWF4LXJvdGF0ZWQtcHJpbmNpcGFsLWNvbXBvbmVudHMtaW4tcikKClBhY2thZ2VzIGZvciB2aXN1YWxpemF0aW9uIG9mIFBDQQoqIGBmdml6X3BjYV9pbmRgIGFuZCBgZnZpel9wY2FfYmlwbG90YCBmcm9tIGBmYWN0b2V4dHJhYCAKCmBgYHtyIGxicWRhdGEtcGNhMi1wcmVwfQojICgwKSBTZWxlY3QgZGF0YSBmb3IgUENBIOKAlCBvbmx5IG51bWVyaWNhbCBjb2x1bW5zCiMgbmFtZXMocXVlc2RhdGEuY2xlYW4pCgojIE1lZGl1bSB0cmltbWVkIHNldCDigJQgcmVtb3ZlcyBnZW5lcmFsIENhbmFkaWFuIHN0ZXJlb3R5cGUgZXhwZXJpZW5jZS9rbm93bGVkZ2UsIGltaXRhdGlvbiwgU291cmNlcyBvZiBDRSwgaG9ja2V5CnF1ZXNkYXRhLnBjYS5tZWQgPC0gc2VsZWN0KHF1ZXNkYXRhLmNsZWFuLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgSUsyLmF1LCBJSzIuYWksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBTRTEuRmFtLm9vdF8xLCBTRTIuRnJlcS5SZWNlbnRfMTpTRTIuRnJlcS5PdmVyYWxsXzEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBQRTIuQ2FuU3BlYWtGcmVxLlJlY2VudF8xOlBFMi5DYW5TcGVha0ZyZXEuT3ZlcmFsbF8xLAogICAgICAgICAgICAgICAgICAgICAgICAgICBNRTQuQ2FuSGVhckZyZXEuUmVjZW50XzE6TUU0LkNhbkhlYXJGcmVxLk92ZXJhbGxfMSkKcXVlc2RhdGEucGNhLm1lZAoKYGBgCgpgYGB7cn0KIyMgKDEpIFJ1biBQYXJhbGxlbCBBbmFseXNpcyB3aXRoIGBwYXJhbmAKIyBTdGFuZGFyZCB3YXkgdG8gZGVjaWRlIG9uIHRoZSBudW1iZXIgb2YgZmFjdG9ycyBvciBjb21wb25lbnRzIG5lZWRlZCBpbiBhbiBGQSBvciBQQ0EuCiMgUHJpbnRzIG91dCBhIHNjcmVlIHBsb3QgYXMgd2VsbCwgd2l0aCB0aGUgcmFuZG9taXplZCBsaW5lICsgdW5hZGp1c3RlZCBsaW5lCnBhcmFuKHF1ZXNkYXRhLnBjYS5tZWQsCiAgICAgIGdyYXBoID0gVFJVRSwgY29sb3IgPSBUUlVFLCAKICAgICAgY29sID0gYygiYmxhY2siLCAicmVkIiwgImJsdWUiKSwgbHR5ID0gYygxLCAyLCAzKSwgbHdkID0gMSwgbGVnZW5kID0gVFJVRSwgCiAgICAgIGZpbGUgPSAiIiwgd2lkdGggPSA2NDAsIGhlaWdodCA9IDY0MCwgZ3JkZXZpY2UgPSAicG5nIiwgc2VlZCA9IDApCmBgYAoKYGBge3IsIHdhcm5pbmc9Rn0KIyMgKDIpIFJ1biBQQ0Egd2l0aCBgRmFjdG9NaW5lUmAKIyBuY3AgPSBudW1iZXIgb2YgY29tcG9uZW50czsgYWRqdXN0IGFmdGVyIGNoZWNraW5nIHRoZSBwYXJhbGxlbCBhbmFseXNpcyBvdXRwdXQKCiMgRmFjdG9NaW5lUiBQQ0EgQ29tbWFuZHMKI3BsYnFQQ0EgICAgICAgICMgbGlzdHMgY29tbWFuZHMKI3BsYnFQQ0EkdmFyICAgICMgdmFyaWFibGVzCiNwbGJxUENBJGluZCAgICAjIGluZGl2aWR1YWxzCiNwbGJxUENBJGNhbGwgICAjIHN1bW1hcnkgc3RhdHMKCmxicVBDQSA8LSBQQ0EocXVlc2RhdGEucGNhLm1lZCwgc2NhbGUudW5pdCA9IFQsIG5jcCA9MiwgZ3JhcGg9RikKCiMjIFJlbGV2YW50IFJhdyBQQ0EgT3V0cHV0CiMgRWlnZW52YWx1ZXMgJiBwZXJjZW50IHZhcmlhbmNlIGFjY291bnRlZCBmb3IKKGVpZ2VudmFsdWVzIDwtIGxicVBDQSRlaWcpCgojIEVpZ2VudmVjdG9ycyAoPUZhY3RvciBtYXRyaXgsIGZhY3RvciBzY29yZSBjb2VmZmljaWVudHM7IHNvbWV0aW1lcyBjYWxsZWQgdGhlIGZhY3RvciwgYnV0IE5PVCBmYWN0b3Igc2NvcmVzKQooZWlnZW52ZWN0b3JzIDwtIGxicVBDQSR2YXIkY29vcmQpCgojIEZhY3RvciBsb2FkaW5ncyAoZWlnZW52ZWN0b3JzIHNjYWxlZCBieSB0aGUgc3F1YXJlIHJvb3Qgb2YgdGhlaXIgYXNzb2NpYXRlZCBlaWdlbnZhbHVlcykKIyBDYWxjdWxhdGUgZmFjdG9yIGxvYWRpbmdzIHVzaW5nIHRoZSBvdXRwdXQgZWlnZW52ZWN0b3JzIGFuZCBlaWdlbnZhbHVlcwpyYXdMb2FkaW5ncyA8LSBzd2VlcChsYnFQQ0EkdmFyJGNvb3JkLDIsc3FydChsYnFQQ0EkZWlnWzE6bmNvbChsYnFQQ0EkdmFyJGNvb3JkKSwxXSksRlVOPSIvIikKcmF3TG9hZGluZ3MKCiMgRmFjdG9yIHNjb3JlcyBmb3IgZWFjaCBzdWJqZWN0IGFuZCBkaW1lbnNpb24gKGFsc286IEluZGl2aWR1YWwgY29vcmRpbmF0ZSBzY29yZXM7IHByaW5jaXBsZSBjb29yZGluYXRlcykKcmF3U2NvcmVzIDwtIGxicVBDQSRpbmQkY29vcmQKCmBgYAoKYGBge3J9CiMjICgzKSBDb25kdWN0IHJvdGF0aW9uIG9uIHRoZSBQQ0EgZmFjdG9yIGxvYWRpbmdzIHdpdGggYEdQQXJvdGF0aW9uYAojIFJvdGF0aW9ucyBhcmUgdHlwaWNhbGx5IGRvbmUgb24gdGhlIHJldGFpbmVkIGNvbXBvbmVudCBmYWN0b3IgbG9hZGluZ3MsIG5vdCBvbiBhbGwgY29tcG9uZW50cyBub3Igb24gdGhlIGVpZ2VudmVjdG9ycwojIFBlcmZvcm1lZCBmb3IgZWFzZSBvZiBpbnRlcnByZXRhdGlvbiwgbWF4aW1pemluZyBmYWN0b3IgbG9hZGluZ3MKKHJvdExvYWRpbmdzIDwtIFZhcmltYXgocmF3TG9hZGluZ3MpJGxvYWRpbmdzKQoKIyBSZWNvdmVyIFJvdGF0aW9uIG1hdHJpeCBmcm9tIGxvYWRpbmdzCiMgQmVjYXVzZSB0aGUgcm90TG9hZGluZ3MgYXJlIGNhbGN1bGF0ZWQgZnJvbSByYXdMb2FkaW5ncyAlKiUgcm90TWF0cml4LCBjYW4gcmVjb3ZlciByb3RNYXRyaXggYnkgcm90TG9hZGluZ3MgImRpdmlkZWQiIGJ5IHJhd0xvYWRpbmdzLCB3aGljaCBpbiBtYXRyaXggbXVsdGlwbGljYXRpb24gaXMgbXVsdGlwbHlpbmcgYnkgdGhlIGludmVyc2UgKHRyYW5zcG9zZSkgCiMgTm90ZTogRm9yIHNvbWUgcmVhc29uLCBjYW4ndCBjYWxsIFZhcmltYXgocmF3TG9hZGluZ3MpJHJvdG1hdCAoanVzdCBnZXQgTlVMTCk7IHRoaXMgcmVjcmVhdGVzIHRoZSBzYW1lIG1hdHJpeCBmcm9tIFZhcmltYXgocmF3TG9hZGluZ3MpCihyb3RNYXRyaXhMIDwtIHQocmF3TG9hZGluZ3MpICUqJSByb3RMb2FkaW5ncykKCiMgQ2FsY3VsYXRlIHJvdGF0ZWQgZmFjdG9yIHNjb3JlcwojIFRoZSBmb3JtdWxhIHNpbXBseSBtdWx0aXBsaWVzIHRoZSBub3JtYWxpemVkIHZhcmlhYmxlIHNjb3JlcyB3aXRoIHRoZSByb3RhdGlvbiBtYXRyaXggdG8gZ2V0IHJvdGF0ZWQgZmFjdG9yIHNjb3JlcwojIEZpcnN0LCB6LXNjb3JlIHRoZSByYXcgc2NvcmVzIHVzaW5nIGJhc2UgUiBzY2FsZSgpCiMgVGhlbiwgbWF0cml4IG11bHRpcGx5IHRoZSBtYXRyaXggb2YgelNjb3JlcyB3aXRoIHRoZSByb3RhdGlvbiBtYXRyaXgKIyBSZXN1bHQgaXMgYSBtYXRyaXggd2l0aCBjb2x1bW5zPWNvbXBvbmVudHMgYW5kIHJvd3M9ZWFjaCBzdWJqZWN0CnpTY29yZXMgPC0gc2NhbGUocmF3U2NvcmVzKQpyb3RTY29yZXMgPC0gelNjb3JlcyAlKiUgcm90TWF0cml4TApgYGAKCiMjIyMgUGxvdCBQQ0EKYGBge3J9CiMjICg0KSBEYXRhIFZpc3VhbGl6YXRpb24gb2YgUmF3IFNjb3JlcyB3aXRoIGBmYWN0b2V4dHJhYAoKIyBQbG90IGluZGl2aWR1YWwgZmFjdG9yIHNjb3Jlcwpmdml6X3BjYV9pbmQobGJxUENBLCBjb2wuaW5kID0gIiMwMEFGQkIiLCByZXBlbCA9IFRSVUUpCgojIEJpcGxvdCwgaW5jbHVkaW5nIGluZGl2aWR1YWwgc2NvcmVzIGFuZCBmYWN0b3IgdmVjdG9ycwpmdml6X3BjYV9iaXBsb3QobGJxUENBLCBsYWJlbCA9ICJhbGwiLCBjb2wuaW5kID0gIiMwMEFGQkIiLCBjb2wudmFyPSJibGFjayIsIGdndGhlbWUgPSB0aGVtZV9taW5pbWFsKCkpCmBgYAoKYGBge3J9CiMjICg1KSBNYW51YWwgUGxvdHMgb2YgUm90YXRlZCBTY29yZXMgd2l0aCBgZ2dwbG90YAoKIyMgQ3JlYXRlIGRhdGFmcmFtZXMgb2YgdGhlIHJvdGF0ZWQgZmFjdG9yIGxvYWRpbmcgYW5kIGZhY3RvciBzY29yZSBtYXRyaWNlcwojIENvbnZlcnQgcm90YXRlZCBmYWN0b3IgbG9hZGluZ3MgbWF0cml4IHRvIGRhdGEgZnJhbWU7IGFkZCB2YXJpYWJsZSBudW1iZXIKcm90TG9hZGluZ3NEYXRhIDwtIGFzLmRhdGEuZnJhbWUocm90TG9hZGluZ3MpCnJvdExvYWRpbmdzRGF0YSA8LSBtdXRhdGUocm90TG9hZGluZ3NEYXRhLCB2YXJpYWJsZSA9IHJvdy5uYW1lcyhyb3RMb2FkaW5ncykpCnJvdExvYWRpbmdzRGF0YSA8LSBtdXRhdGUocm90TG9hZGluZ3NEYXRhLCB2YXJpYWJsZSA9IGZhY3Rvcih2YXJpYWJsZSkpCgojIENvbnZlcnQgcm90YXRlZCBmYWN0b3Igc2NvcmUgbWF0cml4IHRvIGRhdGEgZnJhbWU7IGFkZCBzdWJqZWN0IG51bWJlcgpyb3RTY29yZURhdGEgPC0gYXMuZGF0YS5mcmFtZShyb3RTY29yZXMpCnJvdFNjb3JlRGF0YSA8LSByb3RTY29yZURhdGEgJT4lIG11dGF0ZShzdWJqZWN0ID0gMTpucm93KC4pKQoKIyMgQ3JlYXRlIGJhc2UgcGxvdHMKIyBMb2FkaW5nIHBsb3QKbG9hZGluZ3Bsb3QgPC0gcm90TG9hZGluZ3NEYXRhICU+JSBnZ3Bsb3QoYWVzKHg9RGltLjEsIHk9RGltLjIpKSsKICBnZW9tX3NlZ21lbnQoZGF0YT1yb3RMb2FkaW5nc0RhdGEsIG1hcHBpbmc9YWVzKHg9MCwgeT0wLCB4ZW5kPURpbS4xKjQsIHllbmQ9RGltLjIqNCksIGFycm93PWFycm93KCksIHNpemU9MC41LCBjb2xvcj0iYmxhY2siKSArCiAgZ2VvbV90ZXh0KGRhdGE9cm90TG9hZGluZ3NEYXRhLCBhZXMoeD1EaW0uMSo0LCB5PURpbS4yKjQsIGxhYmVsPXZhcmlhYmxlKSwgY29sb3I9InJlZCIsY2hlY2tfb3ZlcmxhcD1UKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbT1jKC0yLjc1LCAyLjc1KSxicmVha3M9c2VxKC0zLDMsMSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltPWMoLTMuNSwgMy41KSxicmVha3M9c2VxKC0zLDMsMSkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MCwgbGluZXR5cGU9ImRhc2hlZCIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9MCwgbGluZXR5cGU9ImRhc2hlZCIpICsKICBsYWJzKHRpdGxlPSJWYXJpYWJsZXMgLSBQQ0EiLCB4PSJEaW0gMSAoMzYuNCUpIiwgeT0iRGltIDIgKDE3LjclKSIpICsKICBnZ190aGVtZSgpCmxvYWRpbmdwbG90CgojIFNjYXR0ZXIgcGxvdCBvZiBJbmRpdmlkdWFsIGZhY3RvciBzY29yZXMKZGltcGxvdCA9IGdncGxvdChyb3RTY29yZURhdGEsIGFlcyh4PURpbS4xLCB5PURpbS4yKSkrCiAgZ2VvbV9wb2ludChuYS5ybT1UUlVFLCBjb2xvcj0iIzAwQUZCQiIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsPXN1YmplY3QpLGhqdXN0PTEuNSx2anVzdD0xLjUsIGNvbG9yPSIjMDBBRkJCIiwgY2hlY2tfb3ZlcmxhcD1UKSsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltPWMoLTIuNzUsIDIuNzUpLGJyZWFrcz1zZXEoLTMsMywxKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsaW09YygtMy41LCAzLjUpLGJyZWFrcz1zZXEoLTMsMywxKSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdD0wLCBsaW5ldHlwZT0iZGFzaGVkIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdD0wLCBsaW5ldHlwZT0iZGFzaGVkIikgKwogIGxhYnModGl0bGU9IkluZGl2aWR1YWxzIC0gUENBIiwgeD0iRGltIDEgKDM2LjQlKSIsIHk9IkRpbSAyICgxNy43JSkiKSArCiAgZ2dfdGhlbWUoKQpkaW1wbG90CgojIyBNZXJnZSBsb2FkaW5nIGFuZCBzY29yZSBwbG90ID0gQmlwbG90CgojIEJpcGxvdCBvZiBmYWN0b3IgbG9hZGluZ3MgKyBpbmQgZmFjdG9yIHNjb3JlcwpnZ3Bsb3Qocm90U2NvcmVEYXRhLCBhZXMoeD1EaW0uMSwgeT1EaW0uMikpKwogIGdlb21fcG9pbnQobmEucm09VFJVRSwgY29sb3I9IiMwMEFGQkIiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1zdWJqZWN0KSxoanVzdD0xLjUsdmp1c3Q9MS41LCBjb2xvcj0iIzAwQUZCQiIsIGNoZWNrX292ZXJsYXA9VCkrCiAgCiAgIyBPdmVybGF5IGxvYWRpbmcgcGxvdCAoaS5lLiBhcnJvd3MpCiAgZ2VvbV9zZWdtZW50KGRhdGE9cm90TG9hZGluZ3NEYXRhLCBtYXBwaW5nPWFlcyh4PTAsIHk9MCwgeGVuZD1EaW0uMSo0LCB5ZW5kPURpbS4yKjQpLCBhcnJvdz1hcnJvdygpLCBzaXplPTAuNSwgY29sb3I9ImJsYWNrIikgKwogIGdlb21fdGV4dChkYXRhPXJvdExvYWRpbmdzRGF0YSwgYWVzKHg9RGltLjEqNC41LCB5PURpbS4yKjQuNSwgbGFiZWw9dmFyaWFibGUpLCBjb2xvcj0icmVkIixjaGVja19vdmVybGFwPVQsIG51ZGdlX3kgPSAwKSsKCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbT1jKC0yLjc1LCAyLjc1KSxicmVha3M9c2VxKC0zLDMsMSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltPWMoLTMuNSwgMy41KSxicmVha3M9c2VxKC0zLDMsMSkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MCwgbGluZXR5cGU9ImRhc2hlZCIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9MCwgbGluZXR5cGU9ImRhc2hlZCIpICsKICBsYWJzKHRpdGxlPSJCaXBsb3QgLSBQQ0EiLCB4PSJEaW0gMSAoMzYuNCUpIiwgeT0iRGltIDIgKDE3LjclKSIpICsKICBnZ190aGVtZSgpCgpgYGAKCiMjIyMgSW50ZXJwcmV0IFBDQQpgYGB7cn0KIyMgSW50ZXJwcmV0IFBDcyAoRGltZW5zaW9ucykgYmFzZWQgb24gZmFjdG9yIGxvYWRpbmdzCnJvdExvYWRpbmdzLmRmIDwtIGFzLmRhdGEuZnJhbWUocm90TG9hZGluZ3MpICU+JQogIHJvd25hbWVzX3RvX2NvbHVtbiguLCAiVmFyaWFibGVzIikgJT4lCiAgcmVuYW1lKC4sICJQQzEiPSAiRGltLjEiLCAiUEMyIiA9ICJEaW0uMiIpCnJvdExvYWRpbmdzLmRmCmBgYAoKYGBge3J9CiMgUEMxIE9ubHkgQ29udHJpYnV0b3JzCnJvdExvYWRpbmdzLmRmICU+JSBmaWx0ZXIoYWJzKFBDMSkgPiAwLjIpCmBgYAoKCmBgYHtyfQojIFBDMiBPbmx5IENvbnRyaWJ1dG9ycwpyb3RMb2FkaW5ncy5kZiAlPiUgZmlsdGVyKGFicyhQQzIpID4gMC4yKQpgYGAKCmBgYHtyLCB3YXJuaW5nPUZ9CiMgQ2hlY2sgZm9yIG92ZXJsYXBwaW5nIGNvbnRyaWJ1dG9ycwpyb3RMb2FkaW5ncy5kZiAlPiUgZmlsdGVyKGFicyhQQzIpID4gMC4yICYgYWJzKFBDMSkgPiAwLjIpCgojIENoZWNrIGZvciBub24tY29udHJpYnV0b3JzCnJvdExvYWRpbmdzLmRmICU+JSBmaWx0ZXIoYWJzKFBDMikgPCAwLjIgJiBhYnMoUEMxKSA8IDAuMikKYGBgCgoKCiMjIyBGaW5hbGl6ZSBSZXN1bHRzIHcvIFBDQQoKYGBge3J9CiMgRm9yIE1lcmdpbmc6IENvbnZlcnQgcm90YXRlZCBmYWN0b3Igc2NvcmUgbWF0cml4IHRvIGRhdGEgZnJhbWU7IGFkZCBwYXJ0aWNpcGFudElkIChhc3N1bWluZyBvcmRlciBvZiBpbnB1dCBkYXRhZnJhbWUpCmluZFBDQWRhdGEgPC0gcm90U2NvcmVEYXRhICU+JQogIG11dGF0ZShwYXJ0aWNpcGFudElkID0gcXVlc2RhdGEuY2xlYW4kcGFydGljaXBhbnRJZCkgJT4lCiAgcmVuYW1lKENFc2NvcmUgPSBEaW0uMSkgJT4lCiAgcmVuYW1lKFNBc2NvcmUgPSBEaW0uMikKCiMgTWVyZ2UgcGFydGljaXBhbnQgZGF0YSB3aXRoIFBDIHNjb3JlcyAKIyBPbmx5IHNlbGVjdCB0aGUgbWFpbiByZWxldmFudCBzY29yZXMKcXVlc2RhdGEuZmluYWwgPC0gcXVlc2RhdGEuY2xlYW4gJT4lCiAgbWVyZ2UoLiwgaW5kUENBZGF0YSkgJT4lCiAgbXV0YXRlKE1Tc2NvcmUgPSBzY2FsZShTSzIuTWljaHZTdGFuZCkpICU+JQogIG11dGF0ZShFUXNjb3JlID0gc2NhbGUoRVEucmF3cykpICU+JQogIG11dGF0ZV9hdCh2YXJzKEFnZSksIGFzLm51bWVyaWMpICU+JQogIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsIGFzLmZhY3RvcikgJT4lCiAgc2VsZWN0KHBhcnRpY2lwYW50SWQsIGNvbmRpdGlvbklkLCBndWlzZUNvbWJpbmF0aW9uLCBzcGVha2VyT3JkZXIsIEFnZSwgR2VuZGVyLCBFdGhuaWNpdHksIENFc2NvcmUsIFNBc2NvcmUsIE1Tc2NvcmUsIEVRc2NvcmUsIEVRLnJhd3MsIGV2ZXJ5dGhpbmcoKSkKCnN1bW1hcnkocXVlc2RhdGEuZmluYWwpCgpxdWVzZGF0YS5maW5hbAoKIyBXcml0ZSB0byBmaWxlCndyaXRlLmNzdihxdWVzZGF0YS5maW5hbCwgJ2RhdGEvYXhiXzFhX2xicV9kYXRhLmNzdicsIHJvdy5uYW1lcz1GKQoKYGBgCgojIyBTdW1tYXJpemUgRGF0YQojIyMgVGFibGVzCiMjIyMgQWxsIFNjb3JlcwpgYGB7cn0KIyBUb3RhbApxdWVzZGF0YS5maW5hbCAlPiUgc2VsZWN0KHBhcnRpY2lwYW50SWQsIGNvbmRpdGlvbklkLCBndWlzZUNvbWJpbmF0aW9uLCBBZ2UsIEdlbmRlciwgRXRobmljaXR5LCBDRXNjb3JlLCBTQXNjb3JlLCBNU3Njb3JlLCBFUXNjb3JlLCBFUS5yYXdzKSAlPiUKICBzdW1tYXJpc2VfaWYoaXMubnVtZXJpYywgbGlzdChtZWFuID0gbWVhbiwgc2QgPSBzZCwgbWluID0gbWluLCBtYXggPSBtYXgpKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGV2ZXJ5dGhpbmcoKSwgbmFtZXNfdG8gPSBjKCJNZWFzdXJlIiwgIlN0YXQiKSwgbmFtZXNfc2VwID0gIl8iLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUKICBwaXZvdF93aWRlcihNZWFzdXJlLCBuYW1lc19mcm9tID0gIlN0YXQiLCB2YWx1ZXNfZnJvbSA9ICJ2YWx1ZSIpICU+JQogIG11dGF0ZShtZWFuID0gcm91bmQobWVhbiwgZGlnaXRzID0gNikpICU+JQogIG11dGF0ZShncm91cCA9ICJUb3RhbCIpICU+JQogIHNlbGVjdChncm91cCwgZXZlcnl0aGluZygpKQoKYGBgCgoKYGBge3J9CiMgQmFzZWxpbmUKcXVlc2RhdGEuZmluYWwgJT4lIHNlbGVjdChwYXJ0aWNpcGFudElkLCBjb25kaXRpb25JZCwgZ3Vpc2VDb21iaW5hdGlvbiwgQWdlLCBHZW5kZXIsIEV0aG5pY2l0eSwgQ0VzY29yZSwgU0FzY29yZSwgTVNzY29yZSwgRVFzY29yZSwgRVEucmF3cykgJT4lCiAgZmlsdGVyKGd1aXNlQ29tYmluYXRpb24gPT0gImJhc2VsaW5lIikgJT4lCiAgc3VtbWFyaXNlX2lmKGlzLm51bWVyaWMsIGxpc3QobWVhbiA9IG1lYW4sIHNkID0gc2QsIG1pbiA9IG1pbiwgbWF4ID0gbWF4KSkgJT4lIAogIHBpdm90X2xvbmdlcihldmVyeXRoaW5nKCksIG5hbWVzX3RvID0gYygiTWVhc3VyZSIsICJTdGF0IiksIG5hbWVzX3NlcCA9ICJfIiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lCiAgcGl2b3Rfd2lkZXIoTWVhc3VyZSwgbmFtZXNfZnJvbSA9ICJTdGF0IiwgdmFsdWVzX2Zyb20gPSAidmFsdWUiKSAlPiUKICBtdXRhdGUobWVhbiA9IHJvdW5kKG1lYW4sIGRpZ2l0cyA9IDYpKSAlPiUKICBtdXRhdGUoZ3JvdXAgPSAiYmFzZWxpbmUiKSAlPiUKICBzZWxlY3QoZ3JvdXAsIGV2ZXJ5dGhpbmcoKSkKCiMgTWF0Y2gKcXVlc2RhdGEuZmluYWwgJT4lIHNlbGVjdChwYXJ0aWNpcGFudElkLCBjb25kaXRpb25JZCwgZ3Vpc2VDb21iaW5hdGlvbiwgQWdlLCBHZW5kZXIsIEV0aG5pY2l0eSwgQ0VzY29yZSwgU0FzY29yZSwgTVNzY29yZSwgRVFzY29yZSwgRVEucmF3cykgJT4lCiAgZmlsdGVyKGd1aXNlQ29tYmluYXRpb24gPT0gIm1hdGNoIikgJT4lCiAgc3VtbWFyaXNlX2lmKGlzLm51bWVyaWMsIGxpc3QobWVhbiA9IG1lYW4sIHNkID0gc2QsIG1pbiA9IG1pbiwgbWF4ID0gbWF4KSkgJT4lIAogIHBpdm90X2xvbmdlcihldmVyeXRoaW5nKCksIG5hbWVzX3RvID0gYygiTWVhc3VyZSIsICJTdGF0IiksIG5hbWVzX3NlcCA9ICJfIiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lCiAgcGl2b3Rfd2lkZXIoTWVhc3VyZSwgbmFtZXNfZnJvbSA9ICJTdGF0IiwgdmFsdWVzX2Zyb20gPSAidmFsdWUiKSAlPiUKICBtdXRhdGUobWVhbiA9IHJvdW5kKG1lYW4sIGRpZ2l0cyA9IDYpKSAlPiUKICBtdXRhdGUoZ3JvdXAgPSAibWF0Y2giKSAlPiUKICBzZWxlY3QoZ3JvdXAsIGV2ZXJ5dGhpbmcoKSkKCiMgTWlzbWF0Y2gKcXVlc2RhdGEuZmluYWwgJT4lIHNlbGVjdChwYXJ0aWNpcGFudElkLCBjb25kaXRpb25JZCwgZ3Vpc2VDb21iaW5hdGlvbiwgQWdlLCBHZW5kZXIsIEV0aG5pY2l0eSwgQ0VzY29yZSwgU0FzY29yZSwgTVNzY29yZSwgRVFzY29yZSwgRVEucmF3cykgJT4lCiAgZmlsdGVyKGd1aXNlQ29tYmluYXRpb24gPT0gIm1pc21hdGNoIikgJT4lCiAgc3VtbWFyaXNlX2lmKGlzLm51bWVyaWMsIGxpc3QobWVhbiA9IG1lYW4sIHNkID0gc2QsIG1pbiA9IG1pbiwgbWF4ID0gbWF4KSkgJT4lIAogIHBpdm90X2xvbmdlcihldmVyeXRoaW5nKCksIG5hbWVzX3RvID0gYygiTWVhc3VyZSIsICJTdGF0IiksIG5hbWVzX3NlcCA9ICJfIiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lCiAgcGl2b3Rfd2lkZXIoTWVhc3VyZSwgbmFtZXNfZnJvbSA9ICJTdGF0IiwgdmFsdWVzX2Zyb20gPSAidmFsdWUiKSAlPiUKICBtdXRhdGUobWVhbiA9IHJvdW5kKG1lYW4sIGRpZ2l0cyA9IDYpKSAlPiUKICBtdXRhdGUoZ3JvdXAgPSAibWlzbWF0Y2giKSAlPiUKICBzZWxlY3QoZ3JvdXAsIGV2ZXJ5dGhpbmcoKSkKYGBgCgojIyMjIFBDQSBDb250cmlidXRvcnMKYGBge3J9CiNxdWVzZGF0YS5maW5hbC5zdW0gPC0gCiAgcXVlc2RhdGEuZmluYWwgJT4lIGdyb3VwX2J5KGd1aXNlQ29tYmluYXRpb24pICU+JQogIHN1bW1hcml6ZSgjbWVhbkVRID0gbWVhbihFUXNjb3JlKSwgCiAgICAgICAgICAgIG1lYW5JSzIuYXUgPSBtZWFuKElLMi5hdSksIG1lYW5JSzIuYWkgPSBtZWFuKElLMi5haSksIAogICAgICAgICAgICAjbWVhbkRlY2lkZUNhbiA9IG1lYW4oSUsxLkRlY2lkZUNhbmFkYSksIAogICAgICAgICAgICAjbWVhbkVoRmFtID0gbWVhbihTRTEuRmFtLmVoXzEpLCAKICAgICAgICAgICAgbWVhbk9vdEZhbSA9IG1lYW4oU0UxLkZhbS5vb3RfMSksIAogICAgICAgICAgICBtZWFuU0VGcmVxID0gbWVhbihTRTIuRnJlcS5PdmVyYWxsXzEpLCBtZWFuU0VGcmVxLkMgPSBtZWFuKFNFMi5GcmVxLkNoaWxkXzEpLCAKICAgICAgICAgICAgbWVhblNFRnJlcS5SID0gbWVhbihTRTIuRnJlcS5SZWNlbnRfMSksIAogICAgICAgICAgICBtZWFuU0VBY2MgPSBtZWFuKFNFMy5BY2N1cmFjeSkpCgojcXVlc2RhdGEuZmluYWwuc3VtIDwtIAogIHF1ZXNkYXRhLmZpbmFsICU+JSBncm91cF9ieShndWlzZUNvbWJpbmF0aW9uKSAlPiUKICBzdW1tYXJpemUoQ2FuSGVhckZyZXEgPSBtZWFuKE1FNC5DYW5IZWFyRnJlcS5PdmVyYWxsXzEpLCAKICAgICAgICAgICAgQ2FuSGVhckZyZXEuUiA9IG1lYW4oTUU0LkNhbkhlYXJGcmVxLlJlY2VudF8xKSwKICAgICAgICAgICAgQ2FuSGVhckZyZXEuQyA9IG1lYW4oTUU0LkNhbkhlYXJGcmVxLkNoaWxkXzEpLAogICAgICAgICAgICBDYW5TcGVha0ZyZXEgPSBtZWFuKFBFMi5DYW5TcGVha0ZyZXEuT3ZlcmFsbF8xKSwKICAgICAgICAgICAgQ2FuU3BlYWtGcmVxLlIgPSBtZWFuKFBFMi5DYW5TcGVha0ZyZXEuUmVjZW50XzEpLAogICAgICAgICAgICBDYW5TcGVha0ZyZXEuQyA9IG1lYW4oUEUyLkNhblNwZWFrRnJlcS5DaGlsZF8xKSkKYGBgCgojIyMjIFllcy9ObyBSZXNwb25zZXMKYGBge3J9CnF1ZXNkYXRhLmZpbmFsICU+JSBncm91cF9ieShndWlzZUNvbWJpbmF0aW9uKSAlPiUgbXV0YXRlKEVLMS5DYW5TcGVhayA9IGlmZWxzZShFSzEuQ2FuU3BlYWs9PTEsICJ5ZXMiLCAibm8iKSkgJT4lCmNvdW50KEVLMS5DYW5TcGVhaykgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IEVLMS5DYW5TcGVhaywgdmFsdWVzX2Zyb20gPSBuKSAlPiUKICBtdXRhdGUocXVlc3Rpb249IlNwZWFrRGlmZiIpICU+JSByZWxvY2F0ZShxdWVzdGlvbikKCnF1ZXNkYXRhLmZpbmFsICU+JSBncm91cF9ieShndWlzZUNvbWJpbmF0aW9uKSAlPiUgbXV0YXRlKEVLMi5DYW5Qcm9uID0gaWZlbHNlKEVLMi5DYW5Qcm9uPT0xLCAieWVzIiwgIm5vIikpICU+JQpjb3VudChFSzIuQ2FuUHJvbikgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IEVLMi5DYW5Qcm9uLCB2YWx1ZXNfZnJvbSA9IG4pICAlPiUKICBtdXRhdGUocXVlc3Rpb249IlByb25vdW5jZURpZmYiKSAlPiUgcmVsb2NhdGUocXVlc3Rpb24pCgpxdWVzZGF0YS5maW5hbCAlPiUgZ3JvdXBfYnkoZ3Vpc2VDb21iaW5hdGlvbikgJT4lIG11dGF0ZShFSzMuQ2FuQUkgPSBpZmVsc2UoRUszLkNhbkFJPT0xLCAieWVzIiwgIm5vIikpICU+JQpjb3VudChFSzMuQ2FuQUkpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBFSzMuQ2FuQUksIHZhbHVlc19mcm9tID0gbikgJT4lCiAgbXV0YXRlKHByb3AueWVzID0geWVzLyh5ZXMrbm8pKSAgJT4lCiAgbXV0YXRlKHF1ZXN0aW9uPSJhaURpZmYiKSAlPiUgcmVsb2NhdGUocXVlc3Rpb24pCgpxdWVzZGF0YS5maW5hbCAlPiUgZ3JvdXBfYnkoZ3Vpc2VDb21iaW5hdGlvbikgJT4lIG11dGF0ZShFSzQuQ2FuQVUgPSBpZmVsc2UoRUs0LkNhbkFVPT0xLCAieWVzIiwgIm5vIikpICU+JQpjb3VudChFSzQuQ2FuQVUpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBFSzQuQ2FuQVUsIHZhbHVlc19mcm9tID0gbikgICU+JQogIG11dGF0ZShwcm9wLnllcyA9IHllcy8oeWVzK25vKSkgICU+JQogIG11dGF0ZShxdWVzdGlvbj0iYXVEaWZmIikgJT4lIHJlbG9jYXRlKHF1ZXN0aW9uKQpgYGAKCgpgYGB7cn0KIyBPdmVyYWxsIHRvdGFsCnF1ZXNkYXRhLmZpbmFsICU+JSBtdXRhdGUoRUszLkNhbkFJID0gaWZlbHNlKEVLMy5DYW5BST09MSwgInllcyIsICJubyIpKSAlPiUgY291bnQoRUszLkNhbkFJKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gRUszLkNhbkFJLCB2YWx1ZXNfZnJvbSA9IG4pICU+JSBtdXRhdGUocHJvcC55ZXMgPSB5ZXMvKHllcytubykpICAlPiUKICBtdXRhdGUocXVlc3Rpb249ImFpRGlmZiIpICU+JSByZWxvY2F0ZShxdWVzdGlvbikgJT4lCiAgcmJpbmQoLixxdWVzZGF0YS5maW5hbCAlPiUgbXV0YXRlKEVLNC5DYW5BVSA9IGlmZWxzZShFSzQuQ2FuQVU9PTEsICJ5ZXMiLCAibm8iKSkgJT4lIGNvdW50KEVLNC5DYW5BVSkgJT4lCiAgICAgICAgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gRUs0LkNhbkFVLCB2YWx1ZXNfZnJvbSA9IG4pJT4lIG11dGF0ZShwcm9wLnllcyA9IHllcy8oeWVzK25vKSkgICU+JQogICAgICAgICAgbXV0YXRlKHF1ZXN0aW9uPSJhdURpZmYiKSAlPiUgcmVsb2NhdGUocXVlc3Rpb24pCiAgKQoKYGBgCgojIyMgUGxvdHMKIyMjIyBFUSBTY29yZXMKYGBge3J9CiMgRGVuc2l0eSBQbG90IG9mIHNjb3JlIGRpc3RyaWJ1dGlvbnMKcXVlc2RhdGEuZmluYWwgJT4lIG11dGF0ZShndWlzZUNvbWJpbmF0aW9uID0gcGx5cjo6bWFwdmFsdWVzKGd1aXNlQ29tYmluYXRpb24sIGZyb20gPSBjKCJiYXNlbGluZSIsICJtYXRjaCIsICJtaXNtYXRjaCIpLCB0byA9IGMoIk5vLUd1aXNlIiwgIkd1aXNlLU1hdGNoIiwgIkd1aXNlLU1pc21hdGNoIikpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9RVFzY29yZSxmaWxsPWd1aXNlQ29tYmluYXRpb24sY29sb3I9Z3Vpc2VDb21iaW5hdGlvbikpKwogICBnZW9tX2RlbnNpdHkoYWxwaGE9MC4zKSArCiAgbGFicyh0aXRsZT0iIiwgeD0iRVEgU2NvcmUiLCB5PSJDb3VudCIpICsKICBnZ190aGVtZSgpCgpgYGAKYGBge3J9CiMgQnkgR2VuZGVyCmdncGxvdChkYXRhPXF1ZXNkYXRhLmZpbmFsLCBhZXMoeD1HZW5kZXIsIHk9RVFzY29yZSkpICsKICBnZW9tX2JveHBsb3QoYWVzKGxpbmV0eXBlID0gR2VuZGVyKSwgZmlsbD0iZ3JleSIsIGFscGhhPTAuMywgbmEucm09VFJVRSkgKwogIGdnX3RoZW1lKCkKCiMgQnkgR2VuZGVyICsgR3Vpc2UKZ2dwbG90KGRhdGE9cXVlc2RhdGEuZmluYWwsIGFlcyh4PUdlbmRlciwgeT1FUXNjb3JlKSkgKwogIGdlb21fYm94cGxvdChhZXMoZmlsbCA9IGd1aXNlQ29tYmluYXRpb24sIGNvbG9yPWd1aXNlQ29tYmluYXRpb24sIGxpbmV0eXBlPUdlbmRlciksIGFscGhhPTAuMywgbmEucm09VFJVRSkgKwogIGZhY2V0X2dyaWQofmd1aXNlQ29tYmluYXRpb24pICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWdoaWJsaV9wYWxldHRlKCJQb255b01lZGl1bSIpW2MoNiwzLDQpXSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1naGlibGlfcGFsZXR0ZSgiUG9ueW9NZWRpdW0iKVtjKDYsMyw0KV0pICsKICBnZ190aGVtZSgpCgojIEJ5IEd1aXNlCmdncGxvdChkYXRhPXF1ZXNkYXRhLmZpbmFsLCBhZXMoeD1ndWlzZUNvbWJpbmF0aW9uLCB5PUVRc2NvcmUpKSArCiAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsID0gZ3Vpc2VDb21iaW5hdGlvbiwgY29sb3I9Z3Vpc2VDb21iaW5hdGlvbiksIGFscGhhPTAuMywgbmEucm09VFJVRSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9Z2hpYmxpX3BhbGV0dGUoIlBvbnlvTWVkaXVtIilbYyg2LDMsNCldKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWdoaWJsaV9wYWxldHRlKCJQb255b01lZGl1bSIpW2MoNiwzLDQpXSkgKwogIGdnX3RoZW1lKCkKCmBgYAoKIyMjIyBTQSBTY29yZXMKCmBgYHtyfQojIERlbnNpdHkgUGxvdCBvZiBzY29yZSBkaXN0cmlidXRpb25zCnF1ZXNkYXRhLmZpbmFsICU+JSBtdXRhdGUoZ3Vpc2VDb21iaW5hdGlvbiA9IHBseXI6Om1hcHZhbHVlcyhndWlzZUNvbWJpbmF0aW9uLCBmcm9tID0gYygiYmFzZWxpbmUiLCAibWF0Y2giLCAibWlzbWF0Y2giKSwgdG8gPSBjKCJOby1HdWlzZSIsICJHdWlzZS1NYXRjaCIsICJHdWlzZS1NaXNtYXRjaCIpKSkgJT4lCiAgZ2dwbG90KGFlcyh4PVNBc2NvcmUsZmlsbD1ndWlzZUNvbWJpbmF0aW9uLGNvbG9yPWd1aXNlQ29tYmluYXRpb24pKSsKICAgZ2VvbV9kZW5zaXR5KGFscGhhPTAuMykgKwogIGxhYnModGl0bGU9IiIsIHg9IlNBIFNjb3JlIiwgeT0iQ291bnQiKSArCiAgZ2dfdGhlbWUoKQoKYGBgCgpgYGB7cn0KIyBCeSBHZW5kZXIKZ2dwbG90KGRhdGE9cXVlc2RhdGEuZmluYWwsIGFlcyh4PUdlbmRlciwgeT1TQXNjb3JlKSkgKwogIGdlb21fYm94cGxvdChhZXMobGluZXR5cGUgPSBHZW5kZXIpLCBmaWxsPSJncmV5IiwgYWxwaGE9MC4zLCBuYS5ybT1UUlVFKSArCiAgZ2dfdGhlbWUoKQoKIyBCeSBHZW5kZXIgKyBHdWlzZQpnZ3Bsb3QoZGF0YT1xdWVzZGF0YS5maW5hbCwgYWVzKHg9R2VuZGVyLCB5PVNBc2NvcmUpKSArCiAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsID0gZ3Vpc2VDb21iaW5hdGlvbiwgY29sb3I9Z3Vpc2VDb21iaW5hdGlvbiwgbGluZXR5cGU9R2VuZGVyKSwgYWxwaGE9MC4zLCBuYS5ybT1UUlVFKSArCiAgZmFjZXRfZ3JpZCh+Z3Vpc2VDb21iaW5hdGlvbikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9Z2hpYmxpX3BhbGV0dGUoIlBvbnlvTWVkaXVtIilbYyg2LDMsNCldKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWdoaWJsaV9wYWxldHRlKCJQb255b01lZGl1bSIpW2MoNiwzLDQpXSkgKwogIGdnX3RoZW1lKCkKCiMgQnkgR3Vpc2UKZ2dwbG90KGRhdGE9cXVlc2RhdGEuZmluYWwsIGFlcyh4PWd1aXNlQ29tYmluYXRpb24sIHk9U0FzY29yZSkpICsKICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBndWlzZUNvbWJpbmF0aW9uLCBjb2xvcj1ndWlzZUNvbWJpbmF0aW9uKSwgYWxwaGE9MC4zLCBuYS5ybT1UUlVFKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1naGlibGlfcGFsZXR0ZSgiUG9ueW9NZWRpdW0iKVtjKDYsMyw0KV0pICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9Z2hpYmxpX3BhbGV0dGUoIlBvbnlvTWVkaXVtIilbYyg2LDMsNCldKSArCiAgZ2dfdGhlbWUoKQoKYGBgCgojIyMjIENFIFNjb3JlcwoKYGBge3J9CiMgRGVuc2l0eSBQbG90IG9mIHNjb3JlIGRpc3RyaWJ1dGlvbnMKcXVlc2RhdGEuZmluYWwgJT4lIG11dGF0ZShndWlzZUNvbWJpbmF0aW9uID0gcGx5cjo6bWFwdmFsdWVzKGd1aXNlQ29tYmluYXRpb24sIGZyb20gPSBjKCJiYXNlbGluZSIsICJtYXRjaCIsICJtaXNtYXRjaCIpLCB0byA9IGMoIk5vLUd1aXNlIiwgIkd1aXNlLU1hdGNoIiwgIkd1aXNlLU1pc21hdGNoIikpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9Q0VzY29yZSxmaWxsPWd1aXNlQ29tYmluYXRpb24sY29sb3I9Z3Vpc2VDb21iaW5hdGlvbikpKwogICBnZW9tX2RlbnNpdHkoYWxwaGE9MC4zKSArCiAgbGFicyh0aXRsZT0iIiwgeD0iQ0UgU2NvcmUiLCB5PSJDb3VudCIpICsKICBnZ190aGVtZSgpCgpgYGAKCmBgYHtyfQojIEJ5IEdlbmRlcgpnZ3Bsb3QoZGF0YT1xdWVzZGF0YS5maW5hbCwgYWVzKHg9R2VuZGVyLCB5PUNFc2NvcmUpKSArCiAgZ2VvbV9ib3hwbG90KGFlcyhsaW5ldHlwZSA9IEdlbmRlciksIGZpbGw9ImdyZXkiLCBhbHBoYT0wLjMsIG5hLnJtPVRSVUUpICsKICBnZ190aGVtZSgpCgojIEJ5IEdlbmRlciArIEd1aXNlCmdncGxvdChkYXRhPXF1ZXNkYXRhLmZpbmFsLCBhZXMoeD1HZW5kZXIsIHk9Q0VzY29yZSkpICsKICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBndWlzZUNvbWJpbmF0aW9uLCBjb2xvcj1ndWlzZUNvbWJpbmF0aW9uLCBsaW5ldHlwZT1HZW5kZXIpLCBhbHBoYT0wLjMsIG5hLnJtPVRSVUUpICsKICBmYWNldF9ncmlkKH5ndWlzZUNvbWJpbmF0aW9uKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1naGlibGlfcGFsZXR0ZSgiUG9ueW9NZWRpdW0iKVtjKDYsMyw0KV0pICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9Z2hpYmxpX3BhbGV0dGUoIlBvbnlvTWVkaXVtIilbYyg2LDMsNCldKSArCiAgZ2dfdGhlbWUoKQoKIyBCeSBHdWlzZQpnZ3Bsb3QoZGF0YT1xdWVzZGF0YS5maW5hbCwgYWVzKHg9Z3Vpc2VDb21iaW5hdGlvbiwgeT1DRXNjb3JlKSkgKwogIGdlb21fYm94cGxvdChhZXMoZmlsbCA9IGd1aXNlQ29tYmluYXRpb24sIGNvbG9yPWd1aXNlQ29tYmluYXRpb24pLCBhbHBoYT0wLjMsIG5hLnJtPVRSVUUpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWdoaWJsaV9wYWxldHRlKCJQb255b01lZGl1bSIpW2MoNiwzLDQpXSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1naGlibGlfcGFsZXR0ZSgiUG9ueW9NZWRpdW0iKVtjKDYsMyw0KV0pICsKICBnZ190aGVtZSgpCgpgYGAKCiMjIyMgUENBIE91dHB1dCBTY29yZXMKYGBge3J9CgpDU0NFLmJpcGxvdCA8LSBxdWVzZGF0YS5maW5hbCAlPiUgbXV0YXRlKGd1aXNlQ29tYmluYXRpb24gPSBwbHlyOjptYXB2YWx1ZXMoZ3Vpc2VDb21iaW5hdGlvbiwgZnJvbSA9IGMoImJhc2VsaW5lIiwgIm1hdGNoIiwgIm1pc21hdGNoIiksIHRvID0gYygiTm8tR3Vpc2UiLCAiR3Vpc2UtTWF0Y2giLCAiR3Vpc2UtTWlzbWF0Y2giKSkpICU+JQpnZ3Bsb3QoYWVzKHk9Q0VzY29yZSwgeD1TQXNjb3JlLCBjb2xvcj1ndWlzZUNvbWJpbmF0aW9uLCBzaGFwZT1ndWlzZUNvbWJpbmF0aW9uKSkgKyAKICBnZW9tX3BvaW50KG5hLnJtPVRSVUUsIHNpemU9MywgYWxwaGE9MC43KSArCiAgI2dlb21fdGV4dChhZXMobGFiZWw9c3ViamVjdCksaGp1c3Q9MS41LHZqdXN0PTEuNSwgY29sb3I9IiMwMEFGQkIiLCBjaGVja19vdmVybGFwPVQpKwoKICBzY2FsZV94X2NvbnRpbnVvdXMobGltPWMoLTIuNSwgMi41KSxicmVha3M9c2VxKC0zLDMsMSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltPWMoLTMuNSwgMy41KSxicmVha3M9c2VxKC0zLDMsMSkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MCwgbGluZXR5cGU9ImRhc2hlZCIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9MCwgbGluZXR5cGU9ImRhc2hlZCIpICsKICBsYWJzKHk9IkNFIFNjb3JlcyAoUEMxKSIsIHg9IlNBIFNjb3JlcyAoUEMyKSIsIGNvbG9yPSJQYXJ0aWNpcGFudCBHcm91cCIsIHNoYXBlPSJQYXJ0aWNpcGFudCBHcm91cCIpICsKICAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWdoaWJsaV9wYWxldHRlKCJQb255b01lZGl1bSIpW2MoNiwzLDQpXSkgKwogIGdnX3RoZW1lKCkKQ1NDRS5iaXBsb3QKCiNnZ3NhdmUocGF0aD0icGxvdHMiLCBmaWxlbmFtZT0iQ1MtQ0VfZGlzdHJpYnV0aW9uX3Bsb3QucG5nIiwgQ1NDRS5iaXBsb3QsIHdpZHRoPTE2LCBoZWlnaHQ9OCwgdW5pdHMgPSAiaW4iICwgZHBpPTcyKQoKYGBgCgojIyMjIENvcnJlbGF0aW9ucwoKYGBge3J9CnF1ZXNkYXRhLmZpbmFsICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBTQXNjb3JlLCB5ID0gRVFzY29yZSkpICsgCiAgZ2VvbV9wb2ludChzdGF0PSJpZGVudGl0eSIsIGFlcyhjb2xvdXIgPSBmYWN0b3IoR2VuZGVyKSksIGNleD0yKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpICsKCiAgbGFicyh5ID0gIkVRIFNjb3JlIiwgeCA9ICJTQSBTY29yZSIsIGNvbG9yPSJHZW5kZXIiLAogICAgICAgdGl0bGU9IkNvcnJlbGF0aW9uczogQnkgU3BlYWtlciIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWdoaWJsaV9wYWxldHRlKCJQb255b0xpZ2h0IilbYyg0LDMsMildKSsKICBnZ190aGVtZSgpCmBgYAoKYGBge3J9CnF1ZXNkYXRhLmZpbmFsICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBTQXNjb3JlLCB5ID0gQ0VzY29yZSkpICsgCiAgZ2VvbV9wb2ludChzdGF0PSJpZGVudGl0eSIsIGFlcyhjb2xvdXIgPSBmYWN0b3IoR2VuZGVyKSksIGNleD0yKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpICsKCiAgbGFicyh5ID0gIkNFIFNjb3JlIiwgeCA9ICJTQSBTY29yZSIsIGNvbG9yPSJHZW5kZXIiLAogICAgICAgdGl0bGU9IkNvcnJlbGF0aW9uczogQnkgU3BlYWtlciIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWdoaWJsaV9wYWxldHRlKCJQb255b0xpZ2h0IilbYyg0LDMsMildKSsKICBnZ190aGVtZSgpCmBgYAoKYGBge3J9CnF1ZXNkYXRhLmZpbmFsICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBDRXNjb3JlLCB5ID0gRVFzY29yZSkpICsgCiAgZ2VvbV9wb2ludChzdGF0PSJpZGVudGl0eSIsIGFlcyhjb2xvdXIgPSBmYWN0b3IoR2VuZGVyKSksIGNleD0yKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpICsKCiAgbGFicyh5ID0gIkVRIFNjb3JlIiwgeCA9ICJDRSBTY29yZSIsIGNvbG9yPSJHZW5kZXIiLAogICAgICAgdGl0bGU9IkNvcnJlbGF0aW9uczogQnkgU3BlYWtlciIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWdoaWJsaV9wYWxldHRlKCJQb255b0xpZ2h0IilbYyg0LDMsMildKSsKICBnZ190aGVtZSgpCmBgYA==